简体   繁体   中英

String reversal in C++

I am trying to reverse the order of words in a sentence by maintaining the spaces as below.

[this is my test    string] ==> [string test my is    this]

I did in a step by step manner as,

[this is my test    string] - input string
[gnirts    tset ym si siht] - reverse the whole string - in-place
[string    test my is this] - reverse the words of the string - in-place
[string test my is    this] - string-2 with spaces rearranged

Is there any other method to do this ? Is it also possible to do the last step in-place ?

Your approach is fine. But alternatively you can also do:

  • Keep scanning the input for words and spaces
  • If you find a word push it onto stack S
  • If you find space(s) enqueue the number of spaces into a queue Q

After this is done there will be N words on the stack and N-1 numbers in the queue.

While stack not empty do
 print S.pop
 if stack is empty break
 print Q.deque number of spaces
end-while

Here's an approach.

In short, build two lists of tokens you find: one for words, and another for spaces. Then piece together a new string, with the words in reverse order and the spaces in forward order.

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <sstream>
using namespace std;

string test_string = "this is my test    string";

int main()
{
    // Create 2 vectors of strings.  One for words, another for spaces.
    typedef vector<string> strings;
    strings words, spaces;
    // Walk through the input string, and find individual tokens.
    // A token is either a word or a contigious string of spaces.
    for( string::size_type pos = 0; pos != string::npos; )
    {
        // is this a word token or a space token?
        bool is_char = test_string[pos] != ' ';
        string::size_type pos_end_token = string::npos;

        // find the one-past-the-end index for the end of this token
        if( is_char )
            pos_end_token = test_string.find(' ', pos);
        else
            pos_end_token = test_string.find_first_not_of(' ', pos);

        // pull out this token
        string token = test_string.substr(pos, pos_end_token == string::npos ? string::npos : pos_end_token-pos);
        // if the token is a word, save it to the list of words.
        // if it's a space, save it to the list of spaces
        if( is_char )
            words.push_back(token);
        else
            spaces.push_back(token);
        // move on to the next token
        pos = pos_end_token;
    }

    // construct the new string using stringstream
    stringstream ss;
    // walk through both the list of spaces and the list of words,
    // keeping in mind that there may be more words than spaces, or vice versa
    // construct the new string by first copying the word, then the spaces
    strings::const_reverse_iterator it_w = words.rbegin();
    strings::const_iterator it_s = spaces.begin();
    while( it_w != words.rend() || it_s != spaces.end() )
    {
        if( it_w != words.rend() )
            ss << *it_w++;
        if( it_s != spaces.end() )
            ss << *it_s++;
    }

    // pull a `string` out of the results & dump it
    string reversed = ss.str();
    cout << "Input: '" << test_string << "'" << endl << "Output: '" << reversed << "'" << endl;

}

I would rephrase the problem this way:

  • Non-space tokens are reversed, but preserves their original order
    • The 5 non-space tokens 'this', 'is', 'my', 'test', 'string' gets reversed to 'string', 'test', 'my', 'is', 'this'.
  • Space tokens remain in the original order
    • The space tokens ' ', ' ', ' ', ' ' remains in original order between the new order of non-space tokens.

Following is a O(N) solution [N being the length of char array]. Unfortunately, it is not in place as OP wanted, but it does not use additional stack or queue either -- it uses a separate character array as a working space.

Here is a C-ish pseudo code.

work_array = char array with size of input_array
dst = &work_array[ 0 ]

for( i = 1; ; i++) {
   detect i’th non-space token in input_array starting from the back side
   if no such token {
      break;
   }
   copy the token starting at dst
   advance dst by token_size
   detect i’th space-token in input_array starting from the front side
   copy the token starting at dst
   advance dst by token_size
}

// at this point work_array contains the desired output,
// it can be copied back to input_array and destroyed

对于从第一个字到中心字的字,用字长来切换字n - n首先使用分割功能然后进行切换

This pseudocode assumes you don't end the initial string with a blank space, though can be suitably modified for that too.

1.  Get string length; allocate equivalent space for final string; set getText=1

2.  While pointer doesn't reach position 0 of string,

    i.start from end of string, read character by character... 
      a.if getText=1 
       ...until blank space encountered
      b.if getText=0
       ...until not blank space encountered

    ii.back up pointer to previously pointed character

    iii.output to final string in reverse

    iv.toggle getText

3.  Stop

Copy each string in the array and print it in reverse order(i--)

int main()
{
int j=0;
string str;
string copy[80];
int start=0;
int end=0;
cout<<"Enter the String :: ";
getline(cin,str);
cout<<"Entered String is : "<<str<<endl;
for(int i=0;str[i]!='\0';i++)
{
end=s.find(" ",start);
if(end==-1)
{
copy[j]=str.substr(start,(str.length()-start));
break;
}
else
{
copy[j]=str.substr(start,(end-start));
start=end+1;
j++;
i=end;
}
}

for(int s1=j;s1>=0;s1--)
cout<<" "<<copy[s1];
}

All strtok-solutions work not for your example, see above. Try this:

char *wordrev(char *s)
{
  char *y=calloc(1,strlen(s)+1);
  char *p=s+strlen(s);
  while( p--!=s )
    if( *p==32 )
      strcat(y,p+1),strcat(y," "),*p=0;
  strcpy(s,y);
  free(y);
  return s;
}

Too bad stl string doesn't implement push_front. Then you could do this with transform().

#include <string>
#include <iostream>
#include <algorithm>

class push_front
{
public:
   push_front( std::string& s ) : _s(s) {};
   bool operator()(char c) { _s.insert( _s.begin(), c ); return true; };
   std::string& _s;
};

int main( int argc, char** argv )
{

   std::string s1;
   std::string s( "Now is the time for all good men");
   for_each( s.begin(), s.end(), push_front(s1) );

   std::cout << s << "\n";
   std::cout << s1 << "\n";
}

Now is the time for all good men

nem doog lla rof emit eht si woN

I think I'd just tokenize (strtok or CString::Tokanize) the string using the space character. Shove the strings into a vector, than pull them back out in reverse order and concatenate them with a space in between.

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