1.关于概念
逆波兰表达式又叫做后缀表达式。逆波兰表示法是波兰逻辑学家J・卢卡西维兹于1929年首先提出的一种表达式的表示方法 。后来,人们就把用这种表示法写出的表达式称作“逆波兰表达式”。逆波兰表达式把运算量写在前面,把算符写在后面。
以1 + 2
为例
中缀表达式:1+2。 顾名思义,运算符在中间。
前缀表达式:+12。又称波兰表达式,运算符在操作数的前面
后缀表达式:12+。 又称逆波兰表达式。运算符在中间。
对于一个数学表达式,将其转换成后缀表达表达式的过程如下:
2.关于转换
对于给定的表达式,可以根据下面的算法进行求解。
- 1.建立两个栈A,B,A栈用来存放字符串中的左括号以及运算符,B栈用以存放结果。
- 2.遍历字符串,对遍历到的每个元素进行如下规则的判断。
- 3.如果遇到左括号,直接压入A栈。
- 4.如果遇到数字,直接压入B栈。
- 5.如果遇到运算符,需要进行判断。
5.1 如果A栈顶元素为左括号或A栈为空,直接压入A栈。
5.2 如果A栈顶元素优先级小于自身,直接压入A栈。
5.3 如果A栈顶元素优先级大于自身,需要将A栈顶的元素重复移至B栈,直至A栈顶元素优先级不大于自身,最后再压入A栈。 - 6.如果遇到有括号,重复将A栈顶元素移入B栈,直到遇到左括号,最后弹出左括号。
当遍历完整个字符串后,最后将A栈中元素顺序移入B栈,最后发现B栈从栈低至栈顶就是要求解的答案,只需将B栈方向输入即可。
对于如何比较运算符优先级,可以定义一个函数来实现,不同优先级的运算符芳会不同大小的数。
int priorityComparison(char a){
if(a == '*' || a == '/'){
return 2;
}else{
return 1;
}
}
优先级最高的乘除返回2,其余返回1.
转换函数:
void getPolandNums(char *arr,int len){
for(int i=0;i<len;i++){ //遍历字符数组
if(arr[i] == '('){ //1.如果是左括号,压入A
A.push(arr[i]);
}
else if(arr[i]>='0' && arr[i]<='9'){ //2.如果是数字,压入B
B.push(arr[i]);
}
//3.如果是运算符
else if(arr[i]=='+'||arr[i]=='-'||arr[i]=='*'||arr[i]=='/'){
if(A.empty() || A.top() == '('){ //3.1 如果A栈为空或栈顶元素为左括号,压入A
A.push(arr[i]);
}
else if(priorityComparison(A.top()) <= priorityComparison(arr[i])) { //3.2栈顶元素优先级 小于 自身,也压入A
A.push(arr[i]);
}
//3.3栈顶元素优先级 大于 自身,重复把A栈顶的元素移到B,直到A栈顶的优先级不大于自己
else if(priorityComparison(A.top()) > priorityComparison(arr[i])){
while(priorityComparison(A.top()) > priorityComparison(arr[i])){ //重复把优先级高的移走
B.push(A.top());
A.pop();
}
A.push(arr[i]); //移走之后就可以放进来
}
}
//4.如果是右括号
else if(arr[i] == ')'){
while(A.top() != '('){ //把A的元素重复移到B中,直到A栈顶为左括号
B.push(A.top());
A.pop();
}
A.pop();//把栈顶的左括号删除
}
}
//把A剩余的拼接到B
while (A.size()) {
B.push(A.top());
A.pop();
}
//5.把B中的元素移到C(交换顺序)
stack<char> C;
while(B.size()){
C.push(B.top());
B.pop();
}
//输出C
while(C.size()){
cout<<C.top();
C.pop();
}
}
3.关于求值
通过上面的函数,可以拿到一个经过转换后的逆波兰表达式,例如1 2 + 3 4 - *
,它的原表达式为(1+2)*(3-4)
,那么该表达式的值为-3.
要求逆波兰表达式的值,可以遵循以下算法步骤。
- 1.建立一个两个栈AB,一个用来存放数字,一个用来存放运算符。
- 2.遍历字符串,对遍历到的每个元素进行如下规则的判断。
- 3.如果是数字,压入A栈。
- 4.如果是运算符,首先弹出A栈顶元素n1,在弹出新的栈顶元素n2,之后将n1 n2根据运算符执行相应的运算,最后将得到的数据再压入A栈。
当遍历完成,最后A栈只剩一个元素,即要求解的答案。
完整函数如下(保证给定的逆波兰表达式是合法的)
int getsAns(char *arr,int len){
for(int i = 0; i < len; i ++){
if (arr[i] >= '0' && arr[i] <= '9'){
A.push(int(arr[i]-48));
}
else if(arr[i]=='+'||arr[i]=='-'||arr[i]=='*'||arr[i]=='/'){
int n1 = A.top();
A.pop();
int n2 = A.top();
A.pop();
switch (arr[i]) {
case '+':
A.push(n2 + n1); break;
case '-':
A.push(n2 - n1); break;
case '*':
A.push(n2 * n1); break;
case '/':
A.push(n2 / n1); break;
}
}
}
return A.top();
}