栈的使用-四则运算计算器

计算机在计算四则运算表达式时,不能直接计算中缀表达式,而要把表达式转换为逆波兰表达式,然后再进行求解。所以四则运算表达式求解主要分为两个步骤:

  1. 中缀表达式转换为后缀表达式
  2. 计算后缀表达式的值

两个步骤都需要借助栈来完成。下面详细介绍两个步骤的实现思路:

1.中缀表达式转换为后缀表达式

核心思想:
假设我们以字符串形式输入中缀表达式,此时我们还需要一个变量convertRes来储存后缀表达式结果。假设没有空格和制表符等其他额外字符,我们用名为optSymbo的栈来储存运算符,用index来表示当前遍历到的字符位置。

  • 遇到数字,直接缀到convertRes字符串后面。字符索引index指向下一个字符
  • 遇到左括号(,则入栈。字符索引index指向下一个字符
  • 遇到右括号),则栈中必然有左括号,我们不断输出栈顶运算符,直到遇到左括号(。然后弹出左括号,左括号和右括号都不能出现在后缀表达式中。

注意后缀表达式中运算符前后加空格,便于区分符号和数字

  • 遇到+或者-运算符,我们需要查看栈顶是否有优先级大于等于当前+或者-的运算符。很明显只要栈顶有+-*/都需要输出,直到栈为空或者遇到左括号(然后当前运算符存入栈中。
  • 遇到*或者/运算符,还是要查看栈顶是否有大于等于*或者/的运算符,直到遇到左括号或者低于*或者/的运算符。然后当前运算符存入栈中。
  • 最后字符索引遍历完表达式,查看栈中是否有剩余符号,如果有也一并接到convertRes字符串上

2. 计算后缀表达式

计算后缀表达式同样需要借助栈,在这里命名为optNum

核心思想:

  • 遇到数字,从字符串转换为数字后压栈
  • 遇到运算符,提取栈顶的两个数字按照+-*/,四种情况做运算,记住第一个操作数是栈顶往下第二个元素,栈顶元素为第一个操作数,计算完成后压栈即可
  • 最后输出栈顶元素即为最终结果

3.stringstream字符串类

这个类可以实现将原有字符串按照空格分割,这也是为什么前面提到要在运算符和数字之间加空格。读入后缀表达式,然后遇到空格,就将空格前的字符串装入vector数组中,便于后续索引和计算。

4. 四则运算代码

// calculatorNEW.cpp
#include<iostream>
#include<stack>
#include<vector>
#include<string>
#include<sstream>
using namespace std;

class Calculator{
public:
    int solve(string& s)
    {
        //0.中缀表达式转后缀表达式
        int expressionLen = s.size();
        int index = 0;
        string convertRes;
        stack<char>optSymbol;
        while(index < expressionLen)
        {
            if(s[index] == '+' || s[index] == '-')
            {
                convertRes += ' ';//数字后面补空格
                //当前的加减运算符优先级不高于栈中除(以外的运算符
                // while(!optSymbol.empty() && (optSymbol.top() == '+'|| optSymbol.top() == '-' || optSymbol.top() == '*' || optSymbol.top() == '/'))
                while(!optSymbol.empty() && optSymbol.top() != '(')
                {
                    convertRes += optSymbol.top();
                    convertRes += ' ';
                    optSymbol.pop();
                }
                optSymbol.push(s[index++]);
            }
            else if(s[index] == '*' || s[index] == '/')
            {
                convertRes += ' ';
                while(!optSymbol.empty() && (optSymbol.top() == '*' || optSymbol.top() == '/'))
                {
                    convertRes += optSymbol.top();
                    convertRes +=' ';
                    optSymbol.pop();
                }
                optSymbol.push(s[index++]);
            }
            else if(s[index] == '(')
            {
                optSymbol.push(s[index++]);
            }
            else if(s[index] == ')')
            {
                convertRes += ' ';
                while(optSymbol.top() != '(')
                {
                    convertRes += optSymbol.top();
                    convertRes += ' ';
                    optSymbol.pop();
                }
                optSymbol.pop();//弹出左括号
                index++;
            }
            else
            {
                convertRes += s[index++];
            }
        }

        convertRes += ' ';
        while(!optSymbol.empty())
        {
            convertRes += optSymbol.top();
            convertRes += ' ';
            optSymbol.pop();
        }
        stringstream ss(convertRes);
        vector<string>result;
        string temp;
        while(ss >> temp)
        {
            result.push_back(temp);
        }
        //1.查看逆波兰表达式是否正确
        // for(auto r:result)
        // {
        //     cout << r << " ";
        // }
        // cout << endl;
        //2.计算逆波兰表达式得到结果
        index = 0;
        stack<int>optNum;
        int backExpressionLen = result.size();
        while(index < backExpressionLen)
        {
            string temp2 = result[index];
            if(temp2.size() <= 1 && temp2[0] == '+' || temp2[0] == '-' || temp2[0] == '*' || temp2[0] == '/')
            {
                int num1 = optNum.top();
                optNum.pop();
                int num2 = optNum.top();
                optNum.pop();
                switch(temp2[0])
                {
                    case '+':
                        optNum.push(num2 + num1);
                        break;
                    case '-':
                        optNum.push(num2 - num1);
                        break;
                    case '*':
                        optNum.push(num2 * num1);
                        break;
                    case '/':
                        optNum.push(num2 / num1);
                        break;
                }
            }
            else
            {
                optNum.push(stoi(temp2));
            }
            index++;
        }
        return optNum.top();

    }
};

int main()
{
    string s;
    getline(cin ,s);

    Calculator cal;
    cout << cal.solve(s);
    system("pause");
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值