【问题标题】:How to reverse order of words in a string using stack in C++如何使用 C++ 中的堆栈来反转字符串中单词的顺序
【发布时间】:2015-11-22 09:47:35
【问题描述】:

我正在尝试使用 C++ 中的 Stack 来反转字符串中包含的单词的顺序,但我在最终输出中的字符串开头出现空格。

请帮我找出错误并解决它。

这是我的代码:

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

int main()
{
    int number;
    cin >> number; // number of strings to reverse

    for(int i = 0; i <= number; i++)
    {
        string str;
        getline(cin, str); // input

        std::stack<std::string> s; //stack
        string str1 = "";

        for(int i = 0; i <= str.length(); i++)
        {
            if(str[i] == ' ' || str[i] == '\0')
            { // add the word whenever it encounters a space
                s.push(str1); //push the string
                str1 = "";
            }
            else
                str1 += str[i];
        }

        while(!s.empty())
        { // output
            cout << s.top(); // simple displaying without space
            cout << " ";
            s.pop();
        }
    }

    cout << '\n';
}

输入:

2
Reverse this String
OOP and DS

输出:

         String this Reverse 
DS and OOP 

预期输出:

String this Reverse
DS and OOP

【问题讨论】:

  • 我找到了。可以通过修复代码来解决
  • 我应该怎么做? @Creris
  • 您可以使用std::stringstream line(str); 省去一些解析麻烦,然后使用line &gt;&gt; str1; 来获取单词。
  • 您还可以通过使用调试器并单步执行代码来找到错误。
  • cin &gt;&gt; number; 读入一个数字。但要获得该号码,您必须按 Enter。该输入将立即满足getline(cin, str);

标签: c++ stack


【解决方案1】:

您已接近解决方案,但您遇到了不直观的行为。你的问题是当你cin这个数字时,你最后按下的回车键也被后面的getline占用,导致一个空字符串。所以getline 总共给你 3 个字符串,这显然不是你想要的:你想要 2 个,第一个是“反转这个字符串”,第二个是“OOP 和 DS”,仅此而已。你所做的是与 3 合作,因为一开始就有一个“幽灵”。您对i 上的循环使用了“奇怪”的退出条件(通常使用i&lt;number,但您使用了i&lt;=number),这让我认为您一定已经注意到,通过2 次迭代,您跳过了“OOP 和DS” ",并且您尝试解决问题,但您找到了解决方法,而不是应用正确的解决方案。

正如其他人所说,您可以添加cin.ignore(10000,'\n');来解决问题。这样,getline 将捕获正确数量的行(即 2)。那么你要恢复正确的退出条件,也就是

for(int i = 0; i < number; i++)

另一个循环看起来也很可疑:

for(int i = 0; i <= str.length(); i++)

在这里你做了同样的事情(你用&lt;=而不是&lt;)但结果没问题,因为你在字符串末尾读取一个字符,这会给你终止字符'\ 0' 你正在检查,所以没关系。

除此之外,我刚刚在 for 循环中移动了 cout &lt;&lt; endl;,在打印了每个恢复的行之后。哦,我已经将内部循环的变量从i 更改为j:最好避免重复使用相同的名称(i 已被外部循环使用),因为它们可能会造成混淆(尽管在在这种情况下,它们运行良好)。

这是最终结果(我还添加了几个couts 用于调试,但我留下了一些注释):

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

int main()
{
    int number;
    cin >> number; // number of strings to reverse
    cin.ignore(10000,'\n');

    for(int i = 0; i < number; i++)
    {
        string str;
        getline(cin, str); // input
        //cout << "Debug: i = " << i << ", string = " << str << endl;

        std::stack<std::string> s; //stack
        string str1 = "";

        for(int j = 0; j <= str.length(); j++)
        {
            if(str[j] == ' ' || str[j] == '\0')
            { // add the word whenever it encounters a space
                //cout << "Pushing '" << str1 << "'" << endl;
                s.push(str1); //push the string
                str1 = "";
            }
            else
                str1 += str[j];
        }

        while(!s.empty())
        { // output
            cout << s.top(); // simple displaying without space
            cout << " ";
            s.pop();
        }
        cout << endl;
    }

}

【讨论】:

  • 仍然没有打印出所需的输出!!
  • 这个反向,然后是 DS 和 OOP
  • @Tanvi:对不起,但我不明白,我在 ideone.com 上运行它时得到的输出与您问题中的“预期输出”完全匹配。有什么区别?
【解决方案2】:

Fabio Turati 拥有比我更好的理由和更好的措辞,所以在这一点上,我只是将其添加为一个更优雅的解决方案,并展示一些解决 OP 可能遇到的其他陷阱的解决方案。

#include <iostream>
#include <stack>
#include <string>
#include <limits> // needed by std::numeric_limits<std::streamsize>::max()
#include <sstream> // needed by std::stringstream

// my hatred of using namespace std; knows no bounds so I've replaced it, only
// pulling in a few conveniences
using std::cin;
using std::cout;
using std::endl;

int main()
{
    int number; 
    cout << "Please input the number of strings to reverse" << endl;
    // give the user a prompt so they know what to do
    while (! (cin >> number) || number <= 0) // will loop until the user gives
                                             // us a good number and the number
                                             // is not 0
    {
        cin.clear(); // clear the error flag
        cout << "try again, wise guy." << endl; // mock user's stupidity
        cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        // blow away whatever else user typed in up to the EOL or a few 
        // gajillion entered characters, whichever comes first.
    }
    // OK so we finally got a usable number from the user.
    cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    // throw away anything else the user typed because we don't want to reverse it.
    for(unsigned int i = 0; i < number; i++) // reduced the range of the for loop
    {
        std::string str;
        cout << "Please input a strings to reverse" << endl; 
        // let the user know what's expected
        std::getline(cin, str);
        std::stringstream line(str); // allows us to easily split words just like cin
        std::stack<std::string> wordstack; // more descriptive name. Helps in debugging
        std::string word; //more descriptive name

        while (line >> word) // don't need a for loop here anymore
        { //See? Parsing made easy!
            wordstack.push(word); //push the string
        }

        while(!wordstack.empty())
        { // output
            cout << wordstack.top() << " ";
            wordstack.pop();
        }
        cout << endl; // \n does not force the output to the console. endl does,
                      // but  as a result it is much slower. This happens once
                      // per string and makes the output look prettier, so it's
                      // worth it.
    }
}

【讨论】:

  • 我认为将unsigned int 用于number 并不能满足您的要求。如果我输入 -1,它将被静默转换为std::numeric_limits&lt;unsigned int&gt;::max(),通常为 4294967295。我宁愿使用带符号的 int 并验证它是否为正数。然后,我认为验证第一个输入的 while 循环应该是这样的:while ( !(cin &gt;&gt; number) || number &lt;= 0)。除此之外,我喜欢你的方法。你的“解析变得简单”真的很好用!
  • @FabioTurati 第二点是我很愚蠢,将立即修复。第一点……克罗姆。你一定是在跟我开玩笑。刚测试过。你不是在开玩笑。哇。少一个使用它的理由。不过,这里很容易解决。
  • 太棒了。你知道,当我看到 cout &lt;&lt; "try again, wise guy." &lt;&lt; endl; // mock user's stupidity 时,我立刻爱上了你的回答 :-),并试图用错误的输入运行它,只是为了看到这一点。这实际上就是我发现这些问题的原因。我没有因此而投票,但现在我对此毫无保留。顺便说一句,我认为你在给出更有意义的名字和评论方面做得很好。继续加油!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-19
  • 2010-11-03
  • 2011-11-07
  • 2021-11-25
  • 1970-01-01
  • 1970-01-01
  • 2021-07-07
相关资源
最近更新 更多