• 中缀表达式的计算


    中缀表达式的计算

             前面我们分别讨论了《中缀表达式转换为后缀表达式》以及《后缀表达式的计算》,将二者合并一起即为中缀表达式的计算。即中缀表达式的计算包含两个过程:

             1)中缀表达式到后缀表达式的转换

             2)后缀表达式的计算

             其中,第一个过程是用到了一个栈,该栈存储操作符,即为操作符栈。顺序扫描整个中缀表达式,如果是操作数直接存入后缀表达式中,如果是操作符,则根据其优先级进行入栈出栈操作,具体细节可参见《中缀表达式转换为后缀表达式》。

             第二个过程也用到了一个栈,该栈存储操作数,即为操作数栈。其过程是从左到右顺序扫描整个后缀表达式,如果是操作数,则直接入栈,如果是操作符,则对栈中操作数进行弹栈操作,并对其运算,将运算结果重新压入栈中。最终栈中会剩下一个操作数,即为后缀表达式的结果,也就是中缀表达式的结果,具体细节可以参见《后缀表达式的计算》。

             综上所述,中缀表达式的计算前后两个步骤分别各自用了一个栈,前者用到了操作符栈,并顺序扫描中缀表达式,根据操作符优先级进行弹栈入栈操作。后者用到了操作数栈,并顺序扫描后缀表达式,根据操作符进行弹栈操作并运算。

             将之前的两个步骤进行合并,具体程序如下:

    // 中缀表达式的计算
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <string>
    #include <stack>
    #include <map>
    using namespace std;
    
    void get_infix(vector<string>& inf)
    {
        inf.clear();
        string line;
        getline(cin, line);
        istringstream sin(line);
        string tmp;
        while (sin >> tmp)
        {
            inf.push_back(tmp);
        }
    }
    
    void show(const vector<string>& hs)
    {
        for (vector<string>::size_type i = 0; i != hs.size(); ++i)
        {
            cout << hs[i] << ' ';
        }
        cout << endl;
    }
    
    void init_op(map<string, int>& ops)
    {
        ops.clear();
        ops["+"] = 100;
        ops["-"] = 100;
        ops["*"] = 200;
        ops["/"] = 200;
        ops["("] = 1000;
        ops[")"] = 0;
    }
    
    bool is_operator(const string& hs, const map<string, int>& ops)
    {
        map<string, int>::const_iterator cit = ops.find(hs);
        if (cit != ops.end())
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    
    void in2post(const vector<string>& inf, vector<string>& postf, map<string, int>& ops)
    {
        postf.clear();
        stack<string> op_st;
        for (vector<string>::size_type i = 0; i != inf.size(); ++i)
        {
            if (!is_operator(inf[i], ops))
            {
                postf.push_back(inf[i]);
            }
            else
            {
                if (inf[i] == "(")
                {
                    op_st.push(inf[i]);
                }
                else if (inf[i] == ")")
                {
                    while (!op_st.empty())
                    {
                        if (op_st.top() == "(")
                        {
                            op_st.pop();
                        }
                        else
                        {
                            postf.push_back(op_st.top());
                            op_st.pop();
                        }
                    }
                }
                else // 若为其他运算符
                {
                    if (op_st.empty()) // 若为空栈,则直接入栈
                    {
                        op_st.push(inf[i]);
                    }
                    else
                    {
                        if (ops[inf[i]] > ops[op_st.top()])
                        {
                            // 如果当前操作符优先级高于站定操作符优先级
                            // 则直接入栈
                            op_st.push(inf[i]);
                        }
                        else
                        {
                            // 否则弹出栈中优先级大于等于当前操作符优先级
                            // 的操作符,并最后将当前操作符压栈
                            while (!op_st.empty() && ops[op_st.top()] >= ops[inf[i]] && op_st.top() != "(")
                            {
                                /* 等价于 && op_st.top != "("
                                if (op_st.top() == "(")
                                {
                                    // 如果当前栈顶操作符为 "("
                                    // 则终止操作,继续保留 "(" 的栈顶位置
                                    break;
                                }
                                */
                                postf.push_back(op_st.top());
                                op_st.pop();
                            }
                            op_st.push(inf[i]);
                        }
                    }
                }
            }
        }
        while (!op_st.empty())
        {
            postf.push_back(op_st.top());
            op_st.pop();
        }
    }
    
    double cal_post(const vector<string>& postf, const map<string, int>& ops)
    {
        stack<double> or_st;
        double operand = 0.0, a = 0.0, b = 0.0, c = 0.0;
        for (vector<string>::size_type i = 0; i != postf.size(); ++i)
        {
            if (!is_operator(postf[i], ops))
            {
                operand = static_cast<double>(atof(postf[i].c_str()));
                or_st.push(operand);
            }
            else
            {
                switch (postf[i][0])
                {
                case '+':
                    b = or_st.top();
                    or_st.pop();
                    a = or_st.top();
                    or_st.pop();
                    c = a + b;
                    or_st.push(c);
                    break;
                case '-':
                    b = or_st.top();
                    or_st.pop();
                    a = or_st.top();
                    or_st.pop();
                    c = a - b;
                    or_st.push(c);
                    break;
                case '*':
                    b = or_st.top();
                    or_st.pop();
                    a = or_st.top();
                    or_st.pop();
                    c = a * b;
                    or_st.push(c);
                    break;
                case '/':
                    b = or_st.top();
                    or_st.pop();
                    a = or_st.top();
                    or_st.pop();
                    c = a / b;
                    or_st.push(c);
                    break;
                default:
                    break;
                }
            }
        }
        if (or_st.size() == 1)
        {
            return or_st.top();
        }
        else
        {
            return -10000000000000.0;
        }
    }
    
    int main()
    {
        map<string, int> ops;
        init_op(ops);
        vector<string> inf, postf;
    
        while (1)
        {
            get_infix(inf);
            // show(inf);
            
            in2post(inf, postf, ops);
            show(postf);
            
            double ret = cal_post(postf, ops);
            cout << ret << endl << endl;
        }
        
        system("PAUSE");
        return 0;
    }

             目前为止,我们讨论了中缀表达式到后缀表达式的转换、后缀表达式的计算,并且结合二者进行了中缀表达式的计算。我们这里仅仅局限于加减乘除四种运算和包含了括号功能。并且在处理表达式方面我们使用了一些技巧,以便于操作符和操作数的识别。

             后续,我们将围绕四则运算相关内容做更进一步讨论,具体涉及的内容包括:操作符的扩展、表达式合法性的检测、代数式的扩展、词法分析、虚拟机的实现、脚本语言、代码重构等。

  • 相关阅读:
    信息论
    学习抓包
    深入学习垃圾kafka
    share data
    【转载】计算图像相似度——《Python也可以》之一
    聊聊java list的使用特性
    log4j多线程以及分文件输出日志
    【转载】JDBC的连接参数的设置导致rowid自动添加到sql
    背包问题
    【转】【动态规划】01背包问题
  • 原文地址:https://www.cnblogs.com/unixfy/p/3194737.html
Copyright © 2020-2023  润新知