中缀表达式的计算
前面我们分别讨论了《中缀表达式转换为后缀表达式》以及《后缀表达式的计算》,将二者合并一起即为中缀表达式的计算。即中缀表达式的计算包含两个过程:
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; }
目前为止,我们讨论了中缀表达式到后缀表达式的转换、后缀表达式的计算,并且结合二者进行了中缀表达式的计算。我们这里仅仅局限于加减乘除四种运算和包含了括号功能。并且在处理表达式方面我们使用了一些技巧,以便于操作符和操作数的识别。
后续,我们将围绕四则运算相关内容做更进一步讨论,具体涉及的内容包括:操作符的扩展、表达式合法性的检测、代数式的扩展、词法分析、虚拟机的实现、脚本语言、代码重构等。