后缀表达式也叫逆波兰表达式,其求值过程可以用到栈来辅助存储。
假定待求值的后缀表达式为:9 3 1 - 3 * + 10 2 / +,则其求值过程如下:
规则 :遇见数字就压栈。碰见符号就弹栈 两个 进行运算。然后再将运算结果压栈 。依次类推
1、压栈 9 3 1 碰见 - 弹栈 1 3 运算 3-1 运算结果继续压栈 9 2 表达式剩下 3 * + 10 2 / +
下面是代码解读
/*
expression = [9,3 ,1, -, 3, *, +, 10, 2, /, +]
stack = []
1 数字依次压栈 压栈 9 3 1
expression = [ -, 3, *, +, 10, 2, /, +]
stack = [9,3,1]
2.碰见符号弹栈 两个 进行运算 并将运算结果压栈 碰见了 -
弹栈 1 3
运算 3-1
expression = [ 3, *, +, 10, 2, /, +]
stack = [9,2]
依次例推
压栈 3
expression = [ *, +, 10, 2, /, +]
stack = [9,2,3]
弹栈 3 2
运算 3 *2
expression = [ +, 10, 2, /, +]
stack = [9,6]
弹栈 6 9
运算 9 + 6
expression = [ , 10, 2, /, +]
stack = [15]
压栈 10 2
expression = [ /, +]
stack = [15,10,2]
弹栈 2 10
运算 10/2
expression = [ +]
stack = [15,5]
弹栈 5 15
运算 15+5
stack = [20]
*/
上面只是说明了什么是后缀表达式的计算方法。那么后缀表达式是怎么来的呢。
还是用上面的来举例
比如说。有一个中缀表达式 9+(3-1)*3+10/5 他经过一系列的处理之后就变成了 9 3 1 - 3 * + 10 2 / +
中缀表达式转为后缀表达式 9+(3-1)*3+10/5 转 9 3 1 - 3 * + 10 5 / +
规则 :从左到右遍历中缀表达式的每个数字和符号,若是数字就输出。即成为后缀表达式的一部分。若是符号。则判断其与栈顶符号的优先级。是右括号或者优先级低于栈顶符号 (乘除优先加减)则栈顶元素依次出栈并且输出。并将当前符号进栈。一直到最终输入后缀表达式为止。
上面这段话是我从书上抄来的。是有一点难以理解。我总结了一下。如果是数字。就不用管。直接记录到后缀表达式里面 。如果是( 左括号 直接压栈,只有碰见 )右括号才可以弹出前面的一个左括号。如果是+ - 那么除过 ( 左括号 都需要依次弹出(加减乘除)。 如果是乘除。只能弹出乘除 。不能弹出比它优先级小的。
/*
expression = [9,+,(,3,-,1,),*,3,+,10,/,5 ]
stack = []
suffixExpression = []
9 输出 后缀表达式
expression = [+,(,3,-,1,),*,3,+,10,/,5 ]
stack = []
suffixExpression =[9]
+ 栈顶为空 压栈
expression = [ (,3,-,1,),*,3,+,10,/,5 ]
stack = [+ ]
suffixExpression =[9]
( 栈顶为+ 左括号优先级比+高 压栈
expression = [ 3,-,1,),*,3,+,10,/,5 ]
stack = [+ ( ]
suffixExpression =[9]
依次类推
expression = [ -,1,),*,3,+,10,/,5 ]
stack = [+ ( ]
suffixExpression =[9 3 ]
expression = [ 1,),*,3,+,10,/,5 ]
stack = [+,(,- ]
suffixExpression =[9 3 ]
expression = [ ),*,3,+,10,/,5 ]
stack = [+,(,- ]
suffixExpression =[9 3 1]
碰见) 右括号 弹栈 一直找到左括号为止, 左右括号不进入后缀表达式中 目前 栈内 左右括号中间只有- 所以后缀表达式 追加 -
expression = [ *,3,+,10,/,5 ]
stack = [+, ]
suffixExpression =[9 3 1 -]
* 优先级比+高 压栈
expression = [ 3,+,10,/,5 ]
stack = [+, * ]
suffixExpression =[9 3 1 -]
expression = [ +,10,/,5 ]
stack = [+, * ]
suffixExpression =[9 3 1 - 3]
+优先级比* 低 一直弹栈直到 ( 左括号 或者栈为空 弹栈完毕之后压栈
expression = [ 10,/,5 ]
stack = [+ ]
suffixExpression =[9 3 1 - 3 * + ]
expression = [ /,5 ]
stack = [+ ]
suffixExpression =[9 3 1 - 3 * + 10 ]
expression = [ 5 ]
stack = [+ / ]
suffixExpression =[9 3 1 - 3 * + 10 ]
expression = [ ]
stack = [+ / ]
suffixExpression =[9 3 1 - 3 * + 10 5 ]
最后一个元素结束 栈内所有依次弹栈
expression = [ ]
stack = [ ]
suffixExpression =[9 3 1 - 3 * + 10 5 / + ]
*/
明白了中缀表达式转为后缀表达式以及后缀表达式的计算规则后 可以尝试用代码来实现一下
let str = "9+(3-1)*3+10/5"
let printArr = []
let stack = [];
let mapstr = ''
arr = str.split(/[\*\(\)\+\/\-]/)
for (let i = 0; i < arr.length; i++) {
let sy, mlen
if (arr[i]) {
// 数字
mapstr += arr[i]
mlen = mapstr.length
sy = str[mlen]
printArr.push(arr[i]);
mapstr += sy
} else {
//
mlen = mapstr.length
sy = str[mlen]
mapstr += sy
}
if (sy == "(") {
stack.push(sy)
}
else if (sy == ")") {
let item = stack.pop()
while (item != "(") {
printArr.push(item)
item = stack.pop()
}
}
else if (sy == "+") {
let item = stack.pop()
while (item) {
if (item == "(") {
stack.push(item)
item = null;
} else {
printArr.push(item);
item = stack.pop();
}
}
stack.push(sy)
}
else if (sy == "-") {
let item = stack.pop()
while (item) {
if (item == "(") {
stack.push(item)
item = null;
}
else {
printArr.push(item);
item = stack.pop();
}
}
stack.push(sy)
}
else if (sy == "*") {
let item = stack.pop()
while (item) {
if (item == "(") {
stack.push(item)
item = null;
}
else if (item == "*" || item == "/") {
printArr.push(item);
item = stack.pop();
}
else if (item == "+" || item == "-") {
stack.push(item);
item = null;
}
}
stack.push(sy)
}
else if (sy == "/") {
let item = stack.pop()
while (item) {
if (item == "(") {
stack.push(item)
item = null;
}
else if (item == "*" || item == "/") {
printArr.push(item);
item = stack.pop();
}
else if (item == "+" || item == "-") {
stack.push(item);
item = null;
}
}
stack.push(sy)
}
}
let item = stack.pop()
while (item) {
printArr.push(item)
item = stack.pop()
}
for (let i = 0; i < printArr.length; i++) {
let item = printArr[i]
if (item == "+") {
let num2 = stack.pop() * 1
let num1 = stack.pop() * 1
stack.push(num1 + num2)
}
else if (item == "-") {
let num2 = stack.pop() * 1
let num1 = stack.pop() * 1
stack.push(num1 - num2)
}
else if (item == "*") {
let num2 = stack.pop() * 1
let num1 = stack.pop() * 1
stack.push(num1 * num2)
}
else if (item == "/") {
let num2 = stack.pop() * 1
let num1 = stack.pop() * 1
stack.push(num1 / num2)
}
else {
stack.push(item)
}
}
console.log(stack); // [17]