【问题标题】:Evaluate postfix using a stack in C++在 C++ 中使用堆栈评估后缀
【发布时间】:2011-08-03 15:11:07
【问题描述】:
#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”值,但是操作没有成功。

【问题讨论】:

  • 你用的是什么输入法?它在崩溃之前能走多远?如果你的操作栈是空的怎么办?
  • 我们知道您更改了代码。只需对问题发表评论即可。我回应了我的答案的变化:)

标签: c++ stack evaluation postfix-notation


【解决方案1】:

你可能是说

switch(input[i])

改为

switch(operation.top())

【讨论】:

    【解决方案2】:

    更新对代码更改的响应


    我可以确认您更改了代码,但不是很好。

    1. 代码大部分都具有它已经存在的所有缺陷,并且还有一些缺陷。
    2. 您现在将操作数组合成一个字符串流有什么好处?
    3. 您现在打开 (operand1,operand2)...
      • 两者都未初始化
      • (operand1,operand2) 在此上下文中基本上表示 (operand2) (sequence operator)
      • 您的分支标签是 ... 运算符 (+-/*)
    4. 您现在打印一个最终结果,它是输入中所有数字的串联(如果您在没有崩溃的情况下到达程序末尾)?

    在之前的错误中,仍然应该修复

    1. 堆栈计算器的心智模型。
      • 数字(整数)是操作数(因此 9、100、39829 是有效的操作数)
      • +-/* 是运算符(operators 操作 operands
      • 堆栈操作数堆栈,不是运算符堆栈(不必记住运算符,因为它们会立即计算)
      • 数字由连续的 1 个或多个 digits (0123456789) 组成;所以您需要阅读几个字符才能在operand stack 上“推送”number
      • operators +-/* 采用 2 operands,因此任何对大小

    这应该足以让您入门。

    认为有两件事是积极的

    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. 使用相同的循环,但这次打印紧跟相同单词的每个word(所以“不,不,你不应该弹出,弹出,但推,弹出”变成“不弹出”)

    这应该让您了解真正是如何工作的,无需猜测或“魔法因素”。

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


    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
    

    【讨论】:

    • 哦——真是个惊喜。好吧,那我很乐意接受 :)
    • 我没有使用类,因为我几乎不明白它。我改变了:'if (isdigit(input[i])-'0')' 和 'stackoperation' (^.-)
    【解决方案3】:

    代码有很多问题,首先是解析输入表达式。实际崩溃很可能是因为如果您输入类似"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值987654326@...

    【讨论】:

      猜你喜欢
      • 2012-05-01
      • 2013-05-02
      • 2011-12-14
      • 1970-01-01
      • 2020-07-15
      • 2014-07-01
      • 2015-05-03
      • 1970-01-01
      • 2013-10-11
      相关资源
      最近更新 更多