栈的一个重点基础运用就是,四则表达式的求值,这里面困难在于,乘除在加减后面,却要先运算,加入括号后,就变的更加复杂。
波兰逻辑学家想到了一种不需 要括号的后缀表达法,我们也把它称为逆波兰(Reverse Polish Notation, RPN)表示。
对于9+(3-1)*3+10/2,如果用后缀表达式,则为:9 3 1 - 3 * +10 2 / +
。我们先来看看用后缀表达式计算机如何求其值。
一、后缀表达式计算过程
规则:从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是符号,就将处于栈顶两个数字出栈,进行运算,运算结果进栈,一直到最终获得结果
计算过程,初始化一个空栈,前三个都为数字,于是压入,9 3 1,遇到 - 号,被减数3,减数1出栈进行计算,结果为2,此时压入2,接着3入栈,又遇到 * 号,2,3出栈计算,结果为6,6入栈,下面是+ 号,9,6出栈,相加,结果为15,入栈。10,2入栈,遇到 / 号,将两数出栈计算,结果为5,入栈,最后是+ 号,栈中15,5计算,结果为20,而20就是答案。
果然,后缀表达式可以轻松解决问题。那么我们需要得到后缀表达式。
规则:
- 如果当前元素为操作数,则将该元素直接存入到后缀表达式中
- 如果当前元素为“(”,则将其直接入栈;如果为“)”,则将栈中的操作符弹栈,并将弹栈的操作符存入到后缀表达式中,直至遇到“(”,将“(”从栈中弹出,并不将其存入到后缀表达式中
- 如果是其他操作符,如果其优先级高于栈顶操作符的优先级,则将其入栈,如果是小于或等于栈顶操作符优先级,则依次弹出栈顶操作符并存入后缀表达式中,直至遇到一个栈顶优先级小于当前元素优先级时或者栈顶元素为“(”为止,保持当前栈顶元素不变,并将当前元素入栈;
依旧拿上面的 9+(3-1)*3+10/2 分析:
遍历,9输出,+ 栈中为空,入栈,左括号入栈
3输出,- 不高于 + ,入栈,1 输出,当前输出9 3 1
,栈中+ ( -
右括号,- ,(出栈,遇到左括号,输出为9 3 1 -
, 栈中+
符号* 优先级大于+ ,入栈,3输出,当前输出为9 3 1 - 3
,栈中+ *
遇到+,优先级小于,等于+,出栈,+出栈,+入栈,栈中+
,输出为9 3 1 - 3 * +
10输出,/ 优先级大于+,/ 入栈,当前输出为9 3 1 - 3 * + 10
,栈中+ /
2 输出,栈中输出,得到最终结果。 9 3 1 - 3 * + 10 2 / +
;
二、代码实现
下面的代码只是支持一些简单的整数的加减乘除运算,而且不支持浮点数,负数或者数字大于9的数字的运算。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<stack>
using namespace std;
stack< int > q; //算数用的栈
char suffix[30];//后缀表达式
stack< char > p;//符号的栈
void solve()
{
for (int i = 0;i<strlen(suffix) ; i++){
if (suffix[i] >= '0' && suffix[i] <= '9')
q.push(suffix[i] - '0');
else {
int a, b,c;
a = q.top();
q.pop();
b = q.top();
q.pop();
if (suffix[i] == '*')
c = b * a;
else if (suffix[i] == '/')
c = b / a;
else if (suffix[i] == '+')
c = b + a;
else
c = b - a;
q.push(c);
}
}
cout << "结果是" << q.top() << endl;
}
void change(char s[]) //后缀表达式求
{
int j = 0;
for (int i = 0; s[i] != '\0'; i++)
{
if (s[i] >= '0' && s[i] <= '9')
suffix[j++] = s[i];
else{
if (p.size() == 0 || s[i] == '(')
p.push(s[i]);
else
{
if (s[i] == ')'){
while (p.top() != '('){
suffix[j++] = p.top();
p.pop();
}
p.pop();//左括号不输出
}
else if (s[i] == '+' || s[i] == '-'){
while (p.top()!='(') {
//对于加减,只有遇到括号才停止弹出
suffix[j++] = p.top();
p.pop();
if (p.size() == 0||p.top()=='(')
break;
}
p.push(s[i]);
}
else if (s[i] == '*' || s[i] == '/'){
while (p.top()=='*'||p.top()=='/'){
//当栈顶为乘除必定弹出,遇到加减括号则停止
suffix[j++] = p.top();
p.pop();
if (p.size()== 0)
break;
}
p.push(s[i]);
}
}
}
}
while (p.size() != 0){ //将最后的弹出
suffix[j++] = p.top();
p.pop();
}
cout << suffix << endl;}
int main(){
char s[30];
cin >> s;
change(s);
solve();
}