简体   繁体   中英

Reversing A String in C++ (Using Recursion)

#include <iostream>
#include <string>
using namespace std;
void ReverseString(string &S, int size)
{
    static int start = 0;
    if (start == size - 1 || start == size)
    {
        return;
    }
    else
    {
        swap(S[start++], S[size - 1]);
        ReverseString(S, size - 1);
    }
}
int main()
{
    cout << "enter a string to reverse" << endl;
    string s;
    getline(cin, s);
    cout << "Before Reversing" << endl;
    cout << s << endl;
    ReverseString(s, s.size());
    cout << "After Reversing" << endl;
    cout << s << endl;
    return 0;
}

I am trying to nail recursions as much as i can,and i was trying to reverse a string using recursion i didn't know how to do it at first,tried many different ways to do it,but i saw code samples on string reversing,but none of it made sense to me,so i made my own one,but not quite sure of it,i'm just asking for opinion,is it clean and functional??

Thank You

Using a function local static variable in a recursive function is a bad idea. Recursive functions should get all their state as input arguments.

Here's a simplified version that divides the logic into two functions.

void ReverseString(string &S, int start, int end)
{
   if ( start < end )
   {
      swap(S[start], S[end - 1]);
      ReverseString(S, start+1, end - 1);
   }
}

void ReverseString(string &S)
{
   ReverseString(S, 0, S.size());
}

Most of the time, higher level functions would only call the second function. The first function can be called from a higher level function if there is a need to reverse only a subset of a string.

Here's a sample program

#include <iostream>
#include <string>

using namespace std;

void ReverseString(string &S, int start, int end)
{
   if ( start < end )
   {
      swap(S[start], S[end - 1]);
      ReverseString(S, start+1, end - 1);
   }
}

void ReverseString(string &S)
{
   ReverseString(S, 0, S.size());
}

int main()
{
    string s = "The string to reverse" ;

    cout << "Before Reversing" << endl;
    cout << s << endl;

    ReverseString(s);
    cout << "After Reversing" << endl;
    cout << s << endl;

    ReverseString(s, 0, 7);
    cout << "After Reversing a subset" << endl;
    cout << s << endl;
    return 0;
}

and its output

Before Reversing
The string to reverse
After Reversing
esrever ot gnirts ehT
After Reversing a subset
reverse ot gnirts ehT

See it working at https://ideone.com/9nMlsP .

is it ... functional??

If by "functional" you mean "does it work", then you tell me.

If you mean "functional" as in "functional" programming style, then no it isn't. In functional style, you don't modify arguments in place, but instead return a new value. Also relying on global state (ie static objects) is very anti-functional.

Here is an example:

std::string
ReverseString(std::string_view sv)
{
    if (sv.empty())
        return "";
    std::string_view x  = sv.substr(0, 1)
    std::string_view xs = sv.substr(1);
    return ReverseString(xs) + x;
}

// usage
s = ReverseString(s);

In future, if Pattern matching was introduced to the language, then it could potentially be written like this:

std::string
ReverseString(std::string_view sv)
{
    inspect(sv) {
        "":      return "";
        [x:xs]:  return ReverseString(xs) + x;
    }
}

However, the current proposal does not suggest introducing support for matching ranges like this, so this is highly theoretical.

Local static variables are dangerous. Since their state will remain between function calls. In my approach i used slen as the length of a string and the currentIndex as the last swapped index on the string. Since it is enough to swap till the middle of the string, finish case is when (currentIndex == slen/2) . I also added some test cases as an example.(even length, odd length, zero case and palindrome)

#include <iostream>
#include <string>
using namespace std;
void ReverseString(string &S, int currentIndex, int slen)
{
    if (slen / 2 == currentIndex) return;

    swap(S[currentIndex], S[slen - 1 - currentIndex]);
    currentIndex++;

    ReverseString(S, currentIndex, slen);
}

void testReverseString() {
    string s = ""; 
    ReverseString(s, 0, s.length());
    assert(s == "");

    s = "ahmet"; 
    ReverseString(s, 0, s.length());
    assert(s == "temha");

    s = "ahaha"; 
    ReverseString(s, 0, s.length());
    assert(s == "ahaha");

    s = "haha"; 
    ReverseString(s, 0, s.length());
    assert(s == "ahah");
}

int main()
{
    testReverseString();
    return 0;
}

Your function with a static variable can be called only once because after its recursive calls the static variable start will not be equal to 0 as it is required. So the function is not "functional".

Here is a demonstrative program that shows how the function can be written with using a static variable and without using a static variable.

#include <iostream>
#include <string>
#include <utility>

void ReverseString1( std::string &s )
{
    static std::string::size_type i = 0;

    if ( not ( s.size() - 2 * i < 2 ) )
    {
        std::swap( s[i], s[s.size() - i - 1] );

        ++i;
        ReverseString1( s );
        --i;
    }
}

void ReverseString2( std::string &s, std::string::size_type pos = 0 )
{
    if ( not ( s.size() - 2 * pos < 2 ) )
    {
        std::swap( s[pos], s[s.size() - pos - 1] );
        ReverseString2( s, pos + 1 );
    }
}

int main() 
{
    std::string s( "Hello World!" );

    std::cout << s << '\n';

    ReverseString1( s );

    std::cout << s << '\n';

    ReverseString2( s );

    std::cout << s << '\n';

    return 0;
}

The program output is

Hello World!
!dlroW olleH
Hello World!

Anyone can reverse a string one char at a time, but much cooler is to reverse each third of the string and swap the outer thirds. This cuts stack depth as well as sowing confusion amongst the competition. Note that max stack depth of recursion per character is N, whereas this is cube root of N.

#include <iostream>
#include <string>
using namespace std;

void ReverseRegion(string &s, int start, int sz)
{
  // regions < 2 need no action
  if (sz == 2) {
    char tmp = s[start];
    s[start] = s[start+1];
    s[start+1] = tmp;
  } else if (sz > 2) {
    int s3 = sz/3;
    ReverseRegion(s, start, s3);
    string tmp = s.substr(0,start) + s.substr(start+sz-s3,s3) + s.substr(start+s3, sz-2*s3) + s.substr(start,s3) + s.substr(start+sz);
    // cout << "do: " << tmp << "\n";
    s = tmp;
    ReverseRegion(s, start+s3, sz-2*s3);
    ReverseRegion(s, start, s3);
  }
}


void ReverseString(string &S)
{
  ReverseRegion(S, 0, S.size());
}

int main()
{
    cout << "enter a string to reverse" << endl;
    string s;
    getline(cin, s);
    cout << "Before Reversing" << endl;
    cout << s << endl;
    ReverseString(s);
    cout << "After Reversing" << endl;
    cout << s << endl;
    return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM