#include<iostream>
#include<string>
#include<stack>
#include<sstream>
using namespace std; int getP(char ch)
{ //获取优先级 if (ch == '(') return 1; else if (ch == '+' || ch == '-') return 2; else if (ch == '*' || ch == '/') return 3; else return 4;
} void calculate(stack<double> &opnd, char op)
//参数1:当前操作数栈【为什么使用引用符号“&”:引用传递,加快速度】
//参数2:运算符
{ double num1, num2, num3; num2 = opnd.top(); opnd.pop(); num1 = opnd.top(); opnd.pop();if (op == '+') { num3 = num1 + num2; } else if (op == '-') { num3 = num1 - num2; } else if (op == '*') { num3 = num1 * num2; } else if (op == '/') { num3 = num1 / num2; } //思考1:计算过程输出显示cout<<num1<<op<<num2<<"="<<num3<<endl;opnd.push(num3);
} double work(string str)
{ //计算中缀表达式,默认输入是合法的 stack<double> OPND;//操作数栈 类型为double的栈 stack<char> OPTR; //运算符栈 类型为char的栈,存char类型的字符 int i = 0, j; int sz = str.size();//算式长度 char tmp_op; //存放临时存储操作符的变量 string tmp_num; //存放操作数的临时变量 while (i < sz) { if (str[i] >= '0' && str[i] <= '9') {//是操作数 j = i; while (j < sz && ((str[j] >= '0' && str[j] <= '9')||str[j]=='.')) { j++; }//可能是多位数 tmp_num = str.substr(i, j - i); //字符串截取//double t=atoi(tmp_num.c_str());double t;stringstream ss;ss<<tmp_num;ss>>t; // 要把字符串转变为数字,并且入操作数栈OPND.push(t);//cout<<t<<endl;i = j; } else if (str[i] == '+' || str[i] == '-' || str[i] == '*' || str[i] == '/') {//是运算符 if (OPTR.empty()) {//运算符栈为空 ,此时没有必要比较 OPTR.push(str[i]); //直接入栈} else { //不为空,需要对比优先级while (!OPTR.empty()) { tmp_op = OPTR.top();//栈顶操作符(最近一次入栈的操作符) if (getP(tmp_op) >= getP(str[i])) { //如果栈顶运算符优先级大于当前运算符优先级,比如 * > + //计算 calculate(OPND, tmp_op);//此时需要把前面的高优先级运算符[例如乘法]先计算 【必须先乘法再加法,不能拆开算】 OPTR.pop();//这个运算符用过了,可以删掉了 } //开始下一次循环,继续对比else break; //如果栈顶运算符优先级小于当前运算符优先级,那么直接退出,因为:当前运算符优先级高,所以他先计算,他需要的操作数还没有进来。} OPTR.push(str[i]);//当前运算符入栈 } i++; } //思考2:有括号且可嵌套else { //是括号if (str[i] == '(') OPTR.push(str[i]); //左括号直接入栈 else { //是右括号while (OPTR.top() != '(') {//当没有遇到配对的左括号时 tmp_op = OPTR.top(); //取栈顶的操作符//计算 calculate(OPND, tmp_op); //括号内计算 OPTR.pop(); //计算完一次就删掉(出栈)一个运算符} OPTR.pop(); //把最后的左括号也删掉(出栈) } i++; } } //遍历完后,若栈非空,弹出所有元素 while (!OPTR.empty()) { //此时表达式入栈操作已经结束,开始收尾工作【留下的直接按顺序计算就行,因为留下的运算符,储存顺序一定是优先级从小到大的。可参考前面的逻辑进行理解】tmp_op = OPTR.top(); //计算 calculate(OPND, tmp_op); OPTR.pop(); //每计算完一个二元操作符,则弹出该操作符 } return OPND.top();
} int main()
{ string str;cout<<"请输入字符串:"<<endl;cin>>str; double num_res = work(str); cout << "计算结果:" << endl << num_res << endl; system("pause"); return 0;
}