6

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;
}
unknown
  • 4,859
  • 10
  • 44
  • 62
user3370198
  • 73
  • 1
  • 1
  • 6
  • possible duplicate of [Reverse the ordering of words in a string](http://stackoverflow.com/questions/1009160/reverse-the-ordering-of-words-in-a-string) – tenfour Mar 02 '14 at 10:17
  • 1
    How could you even ask this without the webpage warning that it's been asked a million times already? – tenfour Mar 02 '14 at 10:18
  • Shouldn't that for loop signature be: `for (int i = a; i > b+1; i--)` (use `>` instead of `<` and decrement `i`). – David G Mar 02 '14 at 13:50

8 Answers8

5

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!

shafeen
  • 2,431
  • 18
  • 23
  • I don't see why this solution is good. Stack uses extra space. Whereas both the stack approach and normal approach has the same time complexity. – HelloWorld123456789 Mar 02 '14 at 10:03
  • @jaffar : your answer could easily be edited to explain *why* the stack approach leads to cleaner code without spoonfeeding the solution implementation as well. – jlouzado Mar 02 '14 at 11:03
  • Its better to use recursive function to reverse the string then saving the string itself in a stack. – Ankit Singh Mar 02 '14 at 11:53
2

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.

#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.

1

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.

Community
  • 1
  • 1
WeaselFox
  • 7,220
  • 8
  • 44
  • 75
  • 1
    What is the best invention in the world. The axle! – Ed Heal Mar 02 '14 at 07:55
  • While using strtok sounds like a good idea, I wanted to solve this problem in the case of "Reverse 
the
 string
 by 
swapping 
the
 first
character 
with 
the 
last 
character, the 
second 
character 
with 
the
second‐to‐last
character,
 and so on. Then, 
go 
through the 
string
 looking
 for
 spaces.

Reverse
 each
 of 
the 
words
 you 
encounter 
by
 again
 swapping
the 
first
 character
 with
 the
 last
 character, 
the
 second 
character
with
 the
 second‐to‐last
 character,
 and so on" – user3370198 Mar 02 '14 at 09:32
1
// 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;
}
0

Change int length = a-b; 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;
}
HelloWorld123456789
  • 5,299
  • 3
  • 23
  • 33
0
#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)));
}
Shashank
  • 116
  • 1
  • 5
-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;
}
Ankit Singh
  • 2,602
  • 6
  • 32
  • 44
  • You're leaking memory. And why `malloc` instead of `new`? –  Mar 02 '14 at 16:50
  • Used new instead of malloc. Changed in the answer and where I am leaking memory? – Ankit Singh Mar 02 '14 at 17:11
  • In the main function. If you use `new[]`, you need a corresponding `delete[]`. Likewise for `malloc` and `free`. –  Mar 02 '14 at 17:13
-1

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;
}
user110036
  • 1
  • 1
  • 2