简体   繁体   中英

Reverse order of words in string

I am preparing for an entry-level job interview. I am trying to reverse the order of words in a string, but my output is a bunch of junk that makes no sense. I think the problem may be because I'm using "char*" for my functions? Anyways, heres my code

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

char* reverse(char* str, int a, int b); 
char* reversewords(char* str); 

int main()
{
    char str[] = "The interview is";
    cout<<"Reverse is: "<<reversewords(str); 
    cin.ignore();
    return 0;
}


char* reverse(char* str, int a, int b)
{
    int length = a-b;

    for (int i=a; i<b+1; i++)
    {
        char c =str[length-i-1];
        str[length-i-1]=str[i];
        str[i] = c;
    }
    return str;
}

char* reversewords(char* str)
{
    int length = strlen(str);
    int a=0;
    int b=0;
    while (b<length)
    {
        if (str[b]==' ' || b==length-1)
        {
                b=b-1;
            reverse(str, a, b);
            a=b+2;
            b=a;
        }
        b++;
    }
    return str;
}

I would like to reiterate what WeaselFox said about not reinventing the wheel, try to learn the C++ STL, in the long run that will be a lot more helpful.

Having said that let me suggest an approach as well. Whenever you come across problems like reversing order of chars in a string OR reversing words in a string, interviewers are really trying to test your knowledge of data structures, and in this case, specifically the "stack" data structure.

Consider what happens if you parse words in a string and place them all into an array one at a time: "I AM A STRING" --> {"I", "AM", "A", "STRING"}

Now do the same thing for a stack:

"I AM A STRING" --> {"STRING", "A", "AM", "I"}

Do you see why a stack would be useful ? It's better if you reason it out yourself than I provide source code, the reason being that your approach is incorrect regardless of whether or not it yields the correct answer.

I hope this helps!

If you're wanting a C-like solution, you can do it with only pointers and a temp variable of type char if you need to define your own reverse function to reverse a string between two pointers. The code below simply reverses the entire string it receives (it could be modified to reverse only the string in a range [iterA, iterB)) and reverses the letters in each of the word is that string. For example, reversing hello world! first results in !dlrow olleh inside reverse_words , which is corrected to world! hello world! hello .

#include <cstring>
#include <cctype>
using std::isspace;
using std::strlen;

void reverse(char *start, char *end)
{
    for (char c; --end - start > 0; ++start) {
        c = *start;
        *start = *end;
        *end = c;
    }
}

void reverse_words(char *s)
{
    char *end = s + strlen(s);
    char *delimp;

    // Don't reverse any leading/trailing space (e.g. a newline).
    while (isspace(*s))
        ++s;
    while ((isspace(*end) || !*end) && end - s > 0)
        --end;

    // Reverse the remaining string.
    reverse(s, ++end);

    // Reverse each word.
    while (end - s > 0) {

        // Skip leading space characters.
        while (isspace(*s))
            ++s;

        // Find the next space character.
        delimp = s;
        while (!isspace(*delimp) && *delimp)
            ++delimp;

        // Reverse the word.
        reverse(s, delimp);

        // Point to the next space character (or the end of the string).
        s = delimp;
    } //while(end - s > 0)
} //void reverse_words(...)

You could substitute std::reverse in the library for the reverse function defined above. I included an implementation nonetheless. An implementation of reverse_words working on a range could be potentially more useful and shouldn't be difficult to implement with the above code. It is left as an exercise to the reader.

let me recommend a different approach. If youre using char pointers:

  1. split the string using strtok into an array of char* s.
  2. iterate over this array of words from the end backwards and reassemble the string.

If you opt to use strings and STL containers, refer to this question as for splitting the string to tokens, and reassembling them nicely:

Split a string in C++?

Its always a better idea not to reinvent the wheel. Use library functions, dont manipulate the chars yourself.

// Maybe just take the words out of the string and put them back in reverse 
#include <algorithm>
#include <vector>
#include <string>

using namespace std;

int main() {

string a("This is my string to try and reverse");

// Reverse word order
vector<string> words;
string::size_type pos = 1;
while(pos != string::npos) {
    pos = a.find(" ");
    if(pos != string::npos) {
        words.push_back(string(a.begin(),a.begin()+pos));
        a.erase(a.begin(),a.begin()+pos+1);
    }
    else {
        words.push_back(string(a.begin(),a.end()));
        a.erase(a.begin(),a.end());
    }
}
reverse(words.begin(), words.end());
for(int i=0; i<words.size(); i++) a.append(words[i].append(" "));
cout << a << endl;
return 0;
}

Change int length = ab; to int length = b-a+1; in reverse() .

Also you need to loop till middle, otherwise it will be reversed twice, giving the original output.

for (int i=a; i<=a+(b-a)/2; i++)
{
    char c =str[a+length-i-1];
    str[a+length-i-1]=str[i];
    str[i] = c;
}
#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

void split(string &str, vector<string> &v, char ch);

int main() {

string str;
std::getline(std::cin, str);

vector <string> stringVec;

split(str, stringVec, ' ');

vector <string>::reverse_iterator it;

for (auto it = stringVec.rbegin(); it != stringVec.rend(); 
++it)
{
    cout << *it << " ";
}

return 0;
}

void split(string &str, vector<string> &v, char ch)
{
size_t pos = str.find(" ");
size_t initialpos = 0;
v.clear();

while (pos != string::npos)
{
    v.push_back(str.substr(initialpos, pos - initialpos));
    initialpos = pos + 1;
    pos = str.find(ch,initialpos);
}
v.push_back(str.substr(initialpos, (std::min(pos, str.size()) - 
initialpos + 1)));
}

Just to give you headsup for how to reverse a string using RECURSION, I modified your code that is given below. Learn and feel the power of recursion.

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

char * reverse_s(char *, char*, int,int);

int main()
{
    char str[] = "The interview is";
    char* rev_str = new char[strlen(str)];
    cout<<"\n\nFinal Reverse of '" << str << "' is -->"<< reverse_s(str, rev_str, 0, strlen(str)) << endl;
    cin.ignore();
    delete rev_str;
    return 0;
}

char* reverse_s(char* str, char* rev_str, int str_index, int rev_index ) {

if(strlen(str) == str_index )
        return rev_str;

str_index += 1;
rev_index -=1;

rev_str = reverse_s(str, rev_str, str_index, rev_index);

cout << "\n Now the str value is " << str[str_index-1] << " -- Index " << str_index-1;
rev_str[rev_index] = str[str_index-1];

cout << "\nReversed Value: " << rev_str << endl;

return rev_str;
}

here is my version

#include <iostream>
#include <vector> // template for list
#include <algorithm> // copy algorithm or revers
#include <sstream> //sstringstream
#include <iterator>// iterator
#include <fstream>
using namespace std;

/*    overloading ostream operator operator */
ostream &operator<<(ostream&out, const vector<string> a){
static int i = 1;
out << "Case #" << i++ << ": ";

for (vector<string> ::const_iterator v = a.begin(); v != a.end(); v++)
    out << *v;
return out;
}

void showElemnts(vector<string> vec, int line){
cout << "Case #" << line << " " << vec; // overloading operator for output vector
}

vector<string> reversWord(string &s){
istringstream processWordByWord(s); // store string in processWordByWord and store in events
vector<string> events; // store events here
string input;

while (processWordByWord >> input){
    events.push_back(input);
    events.push_back(" ");
}


events.pop_back(); // delete space
reverse(events.begin(), events.end());
return events;
}





int main(){
vector<string> a;
string Line;
ifstream dataInput("B-small-practice.in", ios::in);
ofstream dataOut("out.out");
int  number;

getline(dataInput, Line); // skip first line
getline(dataInput, Line); // skip first line

while (!dataInput.eof())
{
    dataOut << reversWord(Line)<<endl;
    getline(dataInput, Line);


}
dataInput.close();
dataOut.close();

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