中缀表达式就是我们平时见到的算数表达式;前缀表达式被称为波兰式;后缀表达式被称为逆波兰式
中缀表达式转换逆波兰式实现逻辑
- 创建运算符栈operator,结果栈result
- 中缀表达式从左到右出栈
- 当字符为数字时,直接压入result栈
- 当字符为运算符时
- 如果operator栈顶元素优先级不小于当前字符,则将operator栈顶元素出栈,直到operator栈顶元素优先级低于当前元素或遇到‘(’时将当前元素压入operation
- 当前字符为“(”时,直接压入operator
- 当前字符为")“时,将operator栈中的字符依次从栈顶压入result直到遇到第一个”("(停止并删除’(')或栈清空
- 当中缀表达式清空时,将operator栈中的剩余字符依次压入result栈
const calculator = (str) => {
/**
* operator:运算符栈
* result:结果栈
* nowIndex:当前下标
*/
let operator = [], result = [], nowIndex = 0;
const weight = {
'+': 1,
'-': 1,
'*': 2,
'/': 2,
'(': 3,
')': 3,
}
while (str[nowIndex]) {
if (str[nowIndex]) {
if (/\d/.test(+str[nowIndex])) {
// 数字
result.push(str[nowIndex])
} else if (/\(|\)/.test(str[nowIndex])) {
if (str[nowIndex] === '(') {
operator.push(str[nowIndex])
} else {
result.push(operator.pop())
while (operator[operator.length - 1] !== '(') {
result.push(operator.pop())
}
operator.pop()
}
} else if (/[\+\-\*\/]/.test(str[nowIndex])) {
// 符号
let nowTop = operator[operator.length - 1] //最顶层符号
while ((weight[str[nowIndex]] <= weight[nowTop]) && nowTop !== '(') {
result.push(operator.pop())
nowTop = operator[operator.length - 1]
// 也可以通过if判断里nowIndex-- 重新循环,但没有现在这么写节省性能
}
operator.push(str[nowIndex])
}
}
// 一定要写在最后,否正写在上面使用的时候会跳过下标为0的第一个值
nowIndex++
}
while (operator.length) {
result.push(operator.pop())
}
return result.join('')
}
计算逆波兰式实现逻辑
- 遍历逆波兰式,如果遇到数值则按顺序存储到数组中(push),如果遇到符号则用数组中最后两项进行计算并保存到数组中。
const getResult = (str) => {
let arr = str.split('');
console.log(arr)
let resultArr = []; //当前结果
arr.forEach((item, index) => {
if (/\d/.test(+item)) {
// 数字
resultArr.push(+item)
} else {
// 字符
let firstFloor = resultArr.pop();
let secondFloor = resultArr.pop();
switch (item) {
case '+':
resultArr.push(secondFloor + firstFloor);
break;
case '-':
resultArr.push(secondFloor - firstFloor);
break;
case '*':
resultArr.push(secondFloor * firstFloor);
break;
case '/':
resultArr.push(secondFloor / firstFloor);
break;
}
}
})
console.log(resultArr.pop())
}
测试
let jisuan = '1+(2-3)+3-4-(5-1)/2+3*2'
let result = calculator(jisuan);
getResult(result) //3