解题思路:
利用堆栈对表达式求值的方法在任意一本数据结构教科书上都会做明确的阐述。这里简单的回顾:
1.设立两个堆栈,一个用来保存运算符,另一个用来保存数字。
2.在表达式首尾添加标记运算符,该运算符运算优先级最低。
3.从左至右依次遍历字符串,若遍历到运算符,则将其与运算符栈栈顶元素进行比较,若运算符栈栈顶运算符优先级小于该运算符或者此时运算符栈为空,则将该运算符压入堆栈。遍历字符串中下一个元素。
4.若运算符栈栈顶运算符优先级大于该运算符,则弹出该栈顶运算符,再从数字栈中依次弹出两个栈顶数字,完成弹出的运算符对应的运算得到结果后,再将该结果压入数字栈,重复比较此时栈顶运算符与当前遍历到的运算符优先级,视其优先级大小重复步骤 3 或步骤 4。
5.若遍历到表达式中的数字,则直接压入数字栈。
6.若运算符堆栈中仅存有两个运算符且栈顶元素为我们人为添加的标记运算符,那么表达式运算结束,此时数字堆栈中唯一的数字即为表达式的值。
解题要点:
设置结束符:判断一个表达式的结束。
两个栈结构:分别存放数字和运算符。
优先级设置:栈顶运算符就是当前优先级最高的运算符,如果之后的运算符优先级小于栈顶运算符,说明必须执行该栈顶运算符的运算。
AC代码:
#include<cstdio> #include<stack> using namespace std; char str[220];//保存表达式字符串 int mat[][5] = //优先级矩阵,若mat[i][j] == 1,则表示i号运算符优先级大于j号运算符,运算符编码规则为+为1号,-为2号,*为3号,/为4号,我们人为添加在表达式首尾的标记运算符为0号 { 1,0,0,0,0, 1,0,0,0,0, 1,0,0,0,0, 1,1,1,0,0, 1,1,1,0,0, }; stack<int> op;//运算符栈,保存运算符编号 stack<double> in;//数字栈,运算结果可能存在浮点数,所以保存元素为double void getOp(bool &reto, int &retn, int&i)//获得表达式中下一个元素函数,若函数运行结束时,引用变量reto为true,则表示该元素为一个运算符,其编号保存在引用变量retn中; 否则,表示该元素为一个数字,其值保存在引用变量retn中.引用变量i表示遍历到的字符串下标 { if (i == 0 && op.empty() == true)//若此时遍历字符串第一个字符,且运算符栈为空,则我们人为添加编号为0的字符,即循环结束条件 { reto = true;//为运算符 retn = 0;//编号为0 return;//返回 } if (str[i] == 0)//若遍历字符为空字符,表示字符串已被遍历完 { reto = true;//返回为运算符 retn = 0;//编号为0的标记字符 return; } if (str[i] >= '0' && str[i] <= '9')//若当前字符为数字 { reto = false;//返回为数字 } else//否则 { reto = true;//返回为运算符 if (str[i] == '+')retn = 1; else if (str[i] == '-')retn = 2; else if (str[i] == '*')retn = 3; else if (str[i] == '/')retn = 4; i += 2;//i递增,跳过该运算字符和该运算字符后的空格 return; } retn = 0;//返回结果为数字 for (; str[i] != ' '&&str[i] != 0; i++)//若字符串未被遍历完且下一个字符不是空格,则依次遍历后面的数字并计算出连续数字字符表示的数值 { retn *= 10; retn += str[i] - '0'; } if (str[i] == ' ')i++;//其后字符为空格,表示字符串未被遍历完,跳过该空格 return; } int main() { while(gets(str))//输入字符串,当其位于文件尾时,gets返回0 { if (str[0] == '0'&&str[1] == 0)break;//若输入只有一个0,则退出 bool retop; int retnum;//定义函数所需的引用变量 int idx = 0;//定义遍历到的字符串下标,初始值为0 while (!op.empty())op.pop(); while (!in.empty())in.pop();//清空栈 while (true)//循环表达式字符串 { getOp(retop, retnum, idx);//获取表达式中下一个元素 if (retop == false)in.push((double)retnum);//若为数字,压入数字栈 else//否则 { double tmp; if (op.empty() == true || mat[retnum][op.top()] == 1)op.push(retnum);//若运算符栈为空或者当前遍历到的运算符优先级大于栈顶运算符,则将该运算符压栈 else//否则 { while (mat[retnum][op.top()] == 0)//只要当前运算符优先级小于栈顶运算符,重复循环 { int ret = op.top();//保存栈顶运算符 op.pop(); double b = in.top(); in.pop(); double a = in.top(); in.pop();//从数字栈栈顶弹出两个数字在a,b中 if (ret == 1)tmp = a + b; else if (ret == 2)tmp = a - b; else if (ret == 3)tmp = a * b; else tmp = a / b; in.push(tmp);//将结果压回数字栈 } op.push(retnum);//将当前运算符压入运算符栈 } } if (op.size() == 2 && op.top() == 0)break;//运算符栈只有两个元素,且栈顶为标记运算符,表示求值结束 } printf("%.2f ", in.top());//输出数字栈唯一的数字,即为答案 } return 0; }
#include<cstdio> #include<stack> using namespace std; char s[220];//表达式字符串 int mat[][5] = { 1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,1,1,0,0,1,1,1,0,0}; stack<int>op;//运算符栈 stack<double>n;//数字栈,可能有浮点数 void getOp(bool &isop, int &num, int &i) { if (i == 0 && op.empty() == true) { isop = true; num = 0; return;//加入循环终止条件,起始标记运算符 } if (s[i] == 0)//当前遍历字符为空字符,加入终止标记运算符 { isop = true; num = 0; return; } if (s[i] >= '0'&&s[i] <= '9') { isop = false;//返回结果为数字 num = 0; for (; s[i] != ' '&&s[i] != 0; i++) { num *= 10; num += s[i] - '0'; } if (s[i] == ' ')i++;//跳过空格 return; } else { isop = true; if (s[i] == '+')num = 1; else if (s[i] == '-')num = 2; else if (s[i] == '*')num = 3; else if (s[i] == '/')num = 4; i += 2;//跳过该运算符和运算符之后的空格 return; } } int main() { while (gets(s)) { if (s[0] == '0'&&s[1] == 0)break;//若输入只有一个0,则退出 bool isop; int num;//定义函数所需的引用变量 int idx = 0;//定义遍历到的字符串下标,初始值为0 while (!op.empty())op.pop(); while (!n.empty())n.pop();//清空栈 while (true) { getOp(isop, num, idx); if (isop == false)n.push((double)num); else { double tmp; if (op.empty() == true || mat[num][op.top()] == 1)op.push(num); else { while (mat[num][op.top()] == 0) { int ret = op.top();//保存栈顶运算符 op.pop(); double b = n.top(); n.pop(); double a = n.top(); n.pop();//从数字栈栈顶弹出两个数字在a,b中 if (ret == 1)tmp = a + b; else if (ret == 2)tmp = a - b; else if (ret == 3)tmp = a * b; else tmp = a / b; n.push(tmp);//将结果压回数字栈 } op.push(num); } } if (op.size() == 2 && op.top() == 0)break; } printf("%.2f ", n.top());//输出数字栈唯一的数字,即为答案 } return 0; }