程序最美(寻路)

你还在坚持练习你的技术吗?运动员天天训练,音乐家也会演练更难的曲章。你呢?

中缀表达式的计算

中缀表达式的计算

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

         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;
}

 

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

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

posted on 2013-07-17 00:33  unixfy  阅读(1838)  评论(0编辑  收藏  举报

导航