在 C++ 中使用堆栈评估后缀

发布于 2024-10-31 20:50:43 字数 1404 浏览 4 评论 0原文

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

int main()
{
    string input;
    cout << "Enter a postfix expression: " << endl;
    getline(cin, input);

    int operand1, operand2, result,number;
    stack<char>operation;

    stringstream temp;

    int i=0;
    while (i < input.length())
    {
        if (isdigit(input[i]))
        {
            operation.push(input[i]);
        }
        else
        {
            operand2 = operation.top();
            temp << operation.top();
            operation.pop();

            operand1 = operation.top();
            temp << operation.top();
            operation.pop();

            switch(operand1,operand2)
            {
                case '+': result=operand1 + operand2;
                break;

                case '-': result=operand1 - operand2;
                break;

                case '*': result=operand1 * operand2;
                break;

                case '/': result=operand1 / operand2;
                break;
            }
            operation.push(result);
        }
        i++;
    }
    cout << "The result is: "<<temp.str()<<endl;
    cin.ignore(numeric_limits<streamsize>::max(), '\n');

    return 0;
}

我更改了代码并设法获取“pop”值,但操作不起作用。

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

int main()
{
    string input;
    cout << "Enter a postfix expression: " << endl;
    getline(cin, input);

    int operand1, operand2, result,number;
    stack<char>operation;

    stringstream temp;

    int i=0;
    while (i < input.length())
    {
        if (isdigit(input[i]))
        {
            operation.push(input[i]);
        }
        else
        {
            operand2 = operation.top();
            temp << operation.top();
            operation.pop();

            operand1 = operation.top();
            temp << operation.top();
            operation.pop();

            switch(operand1,operand2)
            {
                case '+': result=operand1 + operand2;
                break;

                case '-': result=operand1 - operand2;
                break;

                case '*': result=operand1 * operand2;
                break;

                case '/': result=operand1 / operand2;
                break;
            }
            operation.push(result);
        }
        i++;
    }
    cout << "The result is: "<<temp.str()<<endl;
    cin.ignore(numeric_limits<streamsize>::max(), '\n');

    return 0;
}

I've changed the code and managed to obtain the "pop" value, but the operation didn't work.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

绮筵 2024-11-07 20:50:43

你可能的意思

switch(input[i])

switch(operation.top())

You probably meant

switch(input[i])

instead

switch(operation.top())
假扮的天使 2024-11-07 20:50:43

更新对代码更改的响应


我可以确认您更改了代码,但不是以一种好的方式。

  1. 该代码主要具有它已经存在的所有缺陷,甚至还有一些缺陷。
  2. 现在将操作数组合成字符串流有什么好处?
  3. 您现在打开(操作数1,操作数2)...
  4. 你现在打印最终结果,它是输入中所有数字的串联(如果你到达程序末尾而没有崩溃) ?

在以前错误的事情中,仍然应该修复

  1. 堆栈计算器的心理模型。
    • 数字(整数)是操作数(因此 9、100、39829 是有效操作数)
    • +-/* 是运算符(运算符 操作数进行操作
    • 堆栈操作数堆栈,不是运算符堆栈(运算符不必记住,因为它们会立即计算)
    • 数字由 1 个或多个连续数字 (0123456789) 组成;因此,您需要先读取几个字符,然后才能将数字“压入”操作数堆栈
    • 运算符 +-/* 采用2 操作数,因此对大小<2的堆栈上的任何操作都是错误的(您需要检查这一点,否则程序会在尝试访问不存在或包含垃圾的内存时崩溃)。

这应该足以让您开始。

我认为有两件事是积极的:

  1. 你的程序可以编译。 +1 为您实际上在那里使用编译器:)
  2. 您将重复的 operation.push(result) 从开关中取出,因此它不再重复。编码风格+1...

我希望您可以从中了解到代码不是很好(温和地说),我真的认为一些基本练习是有序的:
1. 编写一个简单的 for 循环,将数字 1 到 10 打印到控制台
1. 编写一个简单的 while 循环来打印用户输入的单词
1. 使用一个简单的循环打印 1 到 50 之间所有 7 的倍数的数字
1. 每当用户输入字母 a、b、k 或 z 之一时,使用 switch 语句打印“yes”
2. 创建一个简单的循环,仅打印相同字符后面的每个字符的输入字符(因此“abccdefgghijkllmabcdd”将变为“cgld”)
1. 使用相同的循环,但这次打印紧随相同单词的每个单词(因此“不,不,你不应该弹出,弹出,而是推,弹出”变成“不弹出”)

这应该会让您感受到事物的实际运作方式,而无需猜测或“神奇因素”。

哦,别忘了,我在下面为您实现了整个过程。我不建议你盲目地复制它(这对你的老师来说是相当明显的:))但是如果你想知道我上面所有的话是什么意思,你可以看一眼:)


  1. 您正在推送松散的数字,而不是已解析的数字

  2. 在第 31 行中,您弹出一个可能为空的堆栈(导致段错误,除非您使用调试模式 STL编译器上的标志)

只是为了好玩:

#include <iostream>
#include <stack>
#include <vector>
#include <limits>
#include <string>
#include <stdexcept>
#include <iterator>
#include <fstream>

using namespace std;

    template <class T>
        static void dumpstack(std::stack<T> s/*byval!*/)
    {
        std::vector<T> vec;

        while (!s.empty())
        {
            vec.push_back(s.top());
            s.pop();
        }

        std::copy(vec.rbegin(), vec.rend(), std::ostream_iterator<int>(std::cout, " "));
    }

    class calc
    {
        private:
            std::stack<int> _stack;
            int _accum;
            bool _pending;

            void store(/*store accumulator if pending*/)
            {
                if (_pending)
                {
                    _stack.push(_accum);
                    _pending = false;
                    _accum = 0;
                }
            }

        public:
            calc() : _accum(0), _pending(false) 
            {
            }

            void handle(char ch)
            {
                switch (ch)
                {
                    case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
                        _pending = true;
                        _accum *= 10;
                        _accum += ch-'0';
                        break;
                    case '+': case '-': case '/': case '*':
                        {
                            store();
                            if (_stack.size()<2)
                                throw std::runtime_error("stack underflow");

                            int op2 = _stack.top(); _stack.pop();
                            int op1 = _stack.top(); _stack.pop();
                            switch (ch)
                            {
                                case '+': _stack.push(op1 + op2); break;
                                case '-': _stack.push(op1 - op2); break;
                                case '/': _stack.push(op1 / op2); break;
                                case '*': _stack.push(op1 * op2); break;
                            }

                            // feedback to console:
                            std::cout << std::endl << "(evaluated: " << op1 << " " << ch << " " << op2 << " == " << _stack.top() << ")" << std::endl;
                            dump();
                        }
                        break;
                    default:
                        store(); // todo: notify of ignored characters in input?
                }
            }

            void dump() const
            {
                dumpstack(_stack);
            }
    };

    int main() 
    {
        cout << "Enter postfix expressions: " << endl;
        calc instance;

        try
        {
            while (std::cin.good())
            {
                char ch = std::cin.get();
                instance.handle(ch);
            }
            std::cout << "Final result: "; 
            instance.dump();

            return 0;
        } catch(const std::exception& e)
        {
            std::cerr << "E: " << e.what() << std::endl;
            return 255;
        }

    }

测试输出:(请注意,您可以继续剩余的、部分评估的、按回车后堆栈)

Enter postfix expressions: 
1 2 3 +4 * - / 1333 *

(evaluated: 2 + 3 == 5)
1 5 
(evaluated: 5 * 4 == 20)
1 20 
(evaluated: 1 - 20 == -19)
-19 E: stack underflow

Update response to code changes


I can confirm you changed the code, but not in a good way.

  1. The code mostly has all the flaws it already had, and a few more.
  2. What good is that you now combine the operands into a stringstream?
  3. You now switch on (operand1,operand2)...
    • both are uninitialized
    • (operand1,operand2) means basically (operand2) in this context (sequence operator)
    • your branch labels are ... operators (+-/*)
  4. you now print a final result which is the concatenation of all digits in the input (if you ever reach the end of the program without crashing)?

Among the things that were wrong before, and should still be fixed

  1. the mental model of a stack calculator.
    • numbers (integers) are the operands (so 9, 100, 39829 are valid operands)
    • +-/* are the operators (operators operate on the operands)
    • the stack is an operand stack, not an operator stack (operators do not have to be remembered, because they are evaluated immediately)
    • numbers consist of 1 or more digits (0123456789) in a row; so you'd need to read several characters before you can 'push' a number on the operand stack
    • the operators +-/* take 2 operands, so any operation on a stack of size<2 is an error (you need to check that or the program will crash while trying to access memory that doesn't exist or contains rubbish).

That should be enough to get you started.

Two things I do think are positive:

  1. You program compiles. +1 for you actually using a compiler there :)
  2. You took the repeated operation.push(result) out of the switch so it isn't duplicated anymore. +1 for coding style ...

I hope you can gather from this that the code isn't very good (to put it mildly), and I really think some basic exercises are in order:
1. write a simple for loop that prints numbers 1 to 10 to the console
1. write a simple while loop that prints words entered by the user
1. use a simple loop to print all numbers between 1 and 50 that are multiples of 7
1. use a switch statement to print "yes" whenever the user enters one of the letters a, b, k, or z
2. make a simple loop that only prints the input character for every character that follows the identical (so 'abccdefgghijkllmabcdd' would become 'cgld')
1. use the same loop but this time print every word that immediately follows the identical word (so "no, no, you should not pop, pop, but push, pop" becomes "no pop")

That should give you a feel for how things really work, without the guesswork or the 'magic factor'.

Oh, and don't forget, I implemented the whole thing for you below. I don't suggest you blindly copy it (it will be rather obvious to your teacher :)) but it is there for you to take a peek if you want to know, what I mean with all my words above :)


  1. You are pushing loose digits, not parsed numbers

  2. In line 31 you pop a possibly empty stack (resulting in segfault unless you use the debug-mode STL flags on your compiler)

Just for fun:

#include <iostream>
#include <stack>
#include <vector>
#include <limits>
#include <string>
#include <stdexcept>
#include <iterator>
#include <fstream>

using namespace std;

    template <class T>
        static void dumpstack(std::stack<T> s/*byval!*/)
    {
        std::vector<T> vec;

        while (!s.empty())
        {
            vec.push_back(s.top());
            s.pop();
        }

        std::copy(vec.rbegin(), vec.rend(), std::ostream_iterator<int>(std::cout, " "));
    }

    class calc
    {
        private:
            std::stack<int> _stack;
            int _accum;
            bool _pending;

            void store(/*store accumulator if pending*/)
            {
                if (_pending)
                {
                    _stack.push(_accum);
                    _pending = false;
                    _accum = 0;
                }
            }

        public:
            calc() : _accum(0), _pending(false) 
            {
            }

            void handle(char ch)
            {
                switch (ch)
                {
                    case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
                        _pending = true;
                        _accum *= 10;
                        _accum += ch-'0';
                        break;
                    case '+': case '-': case '/': case '*':
                        {
                            store();
                            if (_stack.size()<2)
                                throw std::runtime_error("stack underflow");

                            int op2 = _stack.top(); _stack.pop();
                            int op1 = _stack.top(); _stack.pop();
                            switch (ch)
                            {
                                case '+': _stack.push(op1 + op2); break;
                                case '-': _stack.push(op1 - op2); break;
                                case '/': _stack.push(op1 / op2); break;
                                case '*': _stack.push(op1 * op2); break;
                            }

                            // feedback to console:
                            std::cout << std::endl << "(evaluated: " << op1 << " " << ch << " " << op2 << " == " << _stack.top() << ")" << std::endl;
                            dump();
                        }
                        break;
                    default:
                        store(); // todo: notify of ignored characters in input?
                }
            }

            void dump() const
            {
                dumpstack(_stack);
            }
    };

    int main() 
    {
        cout << "Enter postfix expressions: " << endl;
        calc instance;

        try
        {
            while (std::cin.good())
            {
                char ch = std::cin.get();
                instance.handle(ch);
            }
            std::cout << "Final result: "; 
            instance.dump();

            return 0;
        } catch(const std::exception& e)
        {
            std::cerr << "E: " << e.what() << std::endl;
            return 255;
        }

    }

Test output: (note that you can continue with the remaining, partially evaluted, stack after pressing carriage return)

Enter postfix expressions: 
1 2 3 +4 * - / 1333 *

(evaluated: 2 + 3 == 5)
1 5 
(evaluated: 5 * 4 == 20)
1 20 
(evaluated: 1 - 20 == -19)
-19 E: stack underflow
一刻暧昧 2024-11-07 20:50:43

从输入表达式的解析开始,代码有很多问题。实际崩溃很可能是由于以下事实:如果您输入类似 "12+" 的内容,您将推送 '1''2' 到堆栈中(注意:字符 1 和 2,而不是值 1 和 2!!!),然后尝试提取两个操作数一个从未插入到堆栈中的运算符。

在解析输入时,您正在逐个字符地读取,并且仅使用第一个数字,解析无法处理空格或任何其他分隔符...尝试将问题一分为二:解析和处理。解析问题可以通过不使用实际读取的值,而只是打印它们(或以某种形式存储,然后打印整个读取的表达式)来解决,这可以是第一步。确保解析器能够以稳健的方式处理常见表达式,如“1 2 +”、“10 20 +”、“1 2+”、“1 2 +”(注意空格的不同位置)。并且它无法优雅地解析“+”、“1 +”、“1 2 ++”等表达式...您永远不能信任用户输入,他们会犯错误,但这不应该使您的程序崩溃。

一旦确定能够解析输入,就开始实际的算法。使其对您之前可能无法处理的无效用户输入(例如“10 0 /”)具有鲁棒性,并进行实际处理。

学习使用调试器,它将帮助您了解事情出现问题时的原因是什么。调试器将花费不到一秒钟的时间来指出上面代码中的特定问题,它不会告诉您它为什么死掉,但它会向您显示它是如何死掉的以及程序的状态。如果我的预感是正确的,那么它会将您指出 operation.top() 指令作为罪魁祸首,并且您将能够看到您试图提取的元素多于插入的元素。逐步执行程序的一部分以了解它实际上在做什么,您会注意到,当您读取“12+”时,您实际上将两个看似无关的整数存储到堆栈中('1的 ASCII 值) ''2'...

There are many things wrong with the code, starting with parsing of the input expression. The actual crash is most probably due to the fact that if you input something like "12+" you will push '1' and '2' into the stack (note: characters 1 and 2, not values 1 and 2!!!) and then try to extract two operands and an operator that you never inserted into the stack.

On parsing the input, you are reading character by character, and only using the first digit, the parsing is not able to handle spaces or any other separator... Try to break the problem in two: parsing and processing. The problem of parsing can be tackled by not using the actual values read, but just printing them (or storing in some form and then printing the whole read expression), and can be a first step. Ensure that the parser is able to deal with common expressions like "1 2 +", "10 20 +", "1 2+", " 1 2 + " (note the different positions of spaces) in a robust way. And that it fails gracefully to parse expressions like " +", "1 +", "1 2 ++"... You can never trust user input, they will make mistakes and that should not bring your program to its knees.

Once you are sure that you are able to parse the input, start on the actual algorithm. Make it robust against invalid user inputs that you might have not been able to tackle before, like "10 0 /" and do the actual processing.

Learn to use the debugger, it will help you understand when things go south what are the reasons. The debugger would take less than one second to point at the specific problem in your code above, it will not tell you why it died, but it will show you how it died and what the state of the program was there. If my hunch is correct, then it will point you at the operation.top() instruction as the culprit, and you will be able to see that you were trying to extract more elements than were inserted. Execute a part of your program step by step to understand what it is actually doing, and you will notice that when you read "12+" you are actually storing two seemingly unrelated integers into the stack (the ASCII values of '1' and '2'...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文