js用栈实现计算器
使用栈实现计算器的思路
利用栈可以高效处理表达式中的运算符优先级和括号嵌套问题。核心思路是将中缀表达式转换为后缀表达式(逆波兰表达式),再通过栈计算后缀表达式的值。
中缀转后缀的算法步骤
初始化一个运算符栈和一个输出队列(或数组)。从左到右扫描中缀表达式:
遇到数字时直接加入输出队列。
遇到运算符时:
- 若栈顶运算符优先级不低于当前运算符,弹出栈顶运算符并加入输出队列
- 将当前运算符压入栈中
遇到左括号时直接压入栈中。
遇到右括号时:
- 弹出栈顶运算符并加入输出队列,直到遇到左括号
- 弹出左括号但不输出
计算后缀表达式的算法
初始化一个操作数栈。从左到右扫描后缀表达式:
遇到数字时压入操作数栈。
遇到运算符时:
- 弹出栈顶两个数字
- 按运算符计算(注意操作数顺序)
- 将结果压回栈中
JavaScript实现代码
class Stack {
constructor() {
this.items = []
}
push(element) {
this.items.push(element)
}
pop() {
return this.items.pop()
}
peek() {
return this.items[this.items.length - 1]
}
isEmpty() {
return this.items.length === 0
}
}
function infixToPostfix(infix) {
const precedence = {'+':1, '-':1, '*':2, '/':2, '^':3}
const stack = new Stack()
let postfix = []
for(let token of infix.match(/(\d+|\+|\-|\*|\/|\^|\(|\))/g)) {
if(/\d+/.test(token)) {
postfix.push(token)
} else if(token === '(') {
stack.push(token)
} else if(token === ')') {
while(stack.peek() !== '(') {
postfix.push(stack.pop())
}
stack.pop() // 弹出左括号
} else {
while(!stack.isEmpty() && stack.peek() !== '(' &&
precedence[stack.peek()] >= precedence[token]) {
postfix.push(stack.pop())
}
stack.push(token)
}
}
while(!stack.isEmpty()) {
postfix.push(stack.pop())
}
return postfix
}
function evaluatePostfix(postfix) {
const stack = new Stack()
for(let token of postfix) {
if(/\d+/.test(token)) {
stack.push(parseFloat(token))
} else {
const b = stack.pop()
const a = stack.pop()
switch(token) {
case '+': stack.push(a + b); break
case '-': stack.push(a - b); break
case '*': stack.push(a * b); break
case '/': stack.push(a / b); break
case '^': stack.push(Math.pow(a, b)); break
}
}
}
return stack.pop()
}
// 使用示例
const infix = "3+4*2/(1-5)^2"
const postfix = infixToPostfix(infix)
const result = evaluatePostfix(postfix)
console.log(result) // 输出3.5
处理负数的扩展
上述实现不支持负数开头表达式,需预处理:
function preprocessInfix(infix) {
// 将"-"替换为"0-"当它是表达式开头或跟在"("后
return infix.replace(/(^|\(|\+|\-|\*|\/|\^)\s*\-/g, '$10-')
}
// 使用示例
const infix = "-3+4*(-2)"
const processed = preprocessInfix(infix)
const postfix = infixToPostfix(processed)
const result = evaluatePostfix(postfix)
console.log(result) // 输出-11
注意事项
运算符优先级定义影响计算结果,需根据需求调整。
对于浮点数运算,需考虑精度问题,可使用toFixed等方法处理。
大数运算可能需要使用BigInt或其他大数库。







