一、基本概念
1、前缀表达式(波兰表达式)
概念: 前缀表达式是一种没有括号的算术表达式,与中缀表达式不同的是,其将运算符写在前面,运算数写在后面。为纪念其发明者波兰数学家Jan Lukasiewicz,前缀表达式也称为“波兰式”。
例如,- 1 + 2 3,它等价于1-(2+3)。
计算方式:从右到左扫描表达式,若为运算数压入堆栈,若为运算符时,弹出栈顶的两个数,进行运算并将结果入栈。重复上述过程直到表达式最右端。最后运算得出的值即为最终结果。
注意运算顺序为:栈顶元素 -运算符-次顶元素
2、中缀表达式
概念:中缀表达式是最常用的算术表达式形式,运算时需要考虑运算符优先级,符合人类的思维结构和运算习惯,但并不适于计算机,所以往往将中缀表达式改为后缀表达式。
例如:1-(2+3)
3、后缀表达式(逆波兰表达式)
概念:后缀表达式,又称逆波兰式,不包含括号,运算符放在两个运算数的后面,是计算机容易运算的表达式,从左到右进行运算无需考
虑优先级,运算呈线性结构。
例如:123+-
计算方式:从左往右扫描表达式,若为运算数,将运算数入栈,若为运算符,弹出栈顶的两个运算数,计算并将结果入栈。重复上述过程直到表达式最右端。最后结果即为计算结果。
注意运算顺序为:次顶元素 -运算符->栈顶元素
二、后缀表达式计算
// 后缀表达式
suffixCalculator(suffixExpression) {
let list = suffixExpression.split('')
// 创建栈
let stack = []
list.forEach((item) => {
if (/\d+/.test(item)) {
// 若为运算数,则运算数入栈
stack.push(item)
} else {
// 若为运算符,弹出栈顶的两个运算数,计算并将结果入栈
let top1 = parseInt(stack.pop())
let top2 = parseInt(stack.pop())
let res = 0
switch (item) {
case '+':
res = top2 + top1
break
case '-':
res = top2 - top1
break
case '*':
res = top2 * top1
break
case '/':
res = top2 / top1
break
default:
throw new Error('运算符有误')
}
stack.push(res + '')
}
})
console.log('计算结果:', stack.pop())
}
三、中缀表达式转后缀表达式
// 中缀表达式转后缀表达式
function infixToSuffix(infix) {
let symbol = []
let value = []
infix.split('').forEach((item) => {
switch (true) {
case /\d+/.test(item):
// 运算数直接后缀表达式
value.push(item)
break
case /[+\-*/]/.test(item):
while (symbol.length + 1) {
if (!symbol.length || !/[+\-*/]/.test(symbol[symbol.length - 1])) {
// 栈顶为空或非运算符
symbol.push(item)
break
}
if (/[*/]/.test(item) && /[+\-]/.test(symbol[symbol.length - 1])) {
// 当前运算符优先级比栈顶高
symbol.push(item)
break
}
if (/[+\-]/.test(item) && /[*/]/.test(symbol[symbol.length - 1])) {
// 当前运算符优先级比栈顶低,一直出栈,并将出栈字符压入后缀表达式
value.push(symbol.pop())
continue
}
// 等于栈顶
value.push(symbol.pop())
continue
}
break
case /\(/.test(item):
// 左括号直接入栈
symbol.push(item)
break
case /\)/.test(item):
// 直接出栈,将出栈字符依次压入后缀表达式,直到栈顶字符为左括号(右括号与左括号不压入后缀表达式)
while (symbol.length) {
let mid = symbol.pop()
if (mid !== '(') {
value.push(mid)
} else break
}
break
default:
}
})
while (symbol.length) {
value.push(symbol.pop())
}
let suffixExpression = value.reduce((pre, item) => pre + item)
console.log('表达式:', suffixExpression)
return suffixExpression
}