简体   繁体   English

使用C ++中的堆栈评估postfix

[英]Evaluate postfix using a stack in C++

#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. 我已经更改了代码并设法获得了“ pop”值,但是该操作无效。

You probably meant 你可能是说

switch(input[i])

instead 代替

switch(operation.top())

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)... 现在您打开(operand1,operand2)...
    • both are uninitialized 两者都未初始化
    • (operand1,operand2) means basically (operand2) in this context ( sequence operator ) (operand1,operand2)在此上下文中基本上表示(operand2)( 序列运算符
    • 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) 数字(整数)是操作数(因此9、100、39829是有效的操作数)
    • +-/* are the operators ( operators operate on the operands ) + - / *是运营商( operators操作 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; 数字连续包含1个或多个digits (0123456789); so you'd need to read several characters before you can 'push' a number on the operand stack 因此,您需要先读取几个字符,然后才能将number “压入” 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). operators +-/ *接受2个 operands ,因此对大小<2的堆栈进行的任何操作都是错误的(您需要检查该变量,否则程序将在尝试访问不存在或包含垃圾的内存时崩溃)。

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 :) 为您实际使用那里的编译器提供+1 :)
  2. You took the repeated operation.push(result) out of the switch so it isn't duplicated anymore. 您将重复的operation.push(result)从开关中取出,因此不再重复。 +1 for coding style ... +1表示编码样式...

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") 我希望您能从中得出这样的结论:代码不是很好(说得通俗一点),我真的认为一些基本的练习是有序的:1.编写一个简单的for循环,将数字1到10打印到控制台1 。编写一个简单的while循环,以打印用户1.输入的单词。使用简单的循环来打印1到50之间的所有数字,这些数字是7的倍数。每当用户输入以下内容之一时,使用switch语句打印“ yes”。字母a,b,k或z2。创建一个简单的循环,仅打印跟随相同字符的每个字符的输入字符(因此,“ abccdefgghijkllmabcdd”将变为“ cgld”)1.使用相同的循环,但这次每次打印紧跟在相同字(所以“不,不,你不应该啪,啪,但推,弹出”变为“无啪”)

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) 在第31行中,您弹出一个可能为空的堆栈(导致segfault,除非您在编译器上使用调试模式STL标志)

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

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. 实际的崩溃很可能是由于以下事实:如果您输入类似"12+" ,则会将'1''2'压入堆栈(注意:字符1和2,而不是值1和2 !!!)然后尝试提取两个操作数一个从未插入堆栈的运算符。

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. 确保解析器能够以健壮的方式处理常见的表达式,例如“ 1 2 +”,“ 10 20 +”,“ 1 2 +”,“ 1 2 +”(注意空格的不同位置)。 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. 而且它无法优雅地解析“ +”,“ 1 +”,“ 1 2 ++”之类的表达式...您永远不能相信用户输入,它们会出错,并且不应该使您的程序屈服。

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. 使它对于您以前可能无法处理的无效用户输入(例如“ 10 0 /”)具有鲁棒性,并进行实际处理。

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. 如果我的预感是正确的,那么它将使您指向operation.top()指令的罪魁祸首,并且您将能够看到您尝试提取的元素比插入的要多。 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' ... 逐步执行程序的一部分以了解其实际功能,您会注意到,当您读取“ 12+”时,实际上是将两个看似无关的整数存储到堆栈中(ASCII值'1''2' ...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM