这个字符串”2*(1+3-4)“的结果是多少
大家好,我是火焱。
前两天,在抖音上刷到一个计算器魔术,很有意思。
于是拿出手机尝试,发现不太对,为什么我的计算器直接把输入的内容都展示出来了?看评论区发现很多人都有类似的问题。
既然自带的计算器不好使,那就用小程序写一个。
产品描述
计算器的显示区只展示当前的数字,如果按了运算符(+ - * /),再输入数字时,展示当前的新数字,不展示之前输入的内容,按等于(=)号后,展示计算结果。
从程序员视角看,按等于(=) 时,我们拿到的是四则运算的字符串,比如:"1 + 2 * 3 - 4",然后通过代码计算这个字符串的结果,那么如何计算呢?
初步尝试
对于 javascript,很容易想到通过 eval 或者 new Function 实现,可是小程序...
既然捷径走不通,那就用逆波兰表达式来解决,我们来看下表达式的三种表示方法。
三种表示
中缀表达式,就是我们常用的表示方式:1 + 2 * 3 - 4
前缀表达式,也叫波兰表达式,是把操作符放到操作数前边,表示成:- + 1 * 2 3 4,由于后缀表达式操作起来比较方便,我们重点看下后缀表达式;
后缀表达式,也叫逆波兰表达式,它是把操作符放到操作数后边,表示成:1 2 3 * + 4 -,有了后缀表达式,我们就可以很容易计算结果了,那如何将中缀表达式转化成后序表达式呢?语言表述比较乏力,直接看代码吧,逻辑比较清晰:
/** 中缀表达式 转 后缀表达式 */
function infixToPostfix(infixExpression) {
let output = [];
// 存放运算符
let stack = [];
for (let i = 0; i < infixExpression.length; i++) {
let char = infixExpression[i];
if (!isOperator(char)) { // char 是数字
output.push(char);
} else { // char 是运算符
while (
// 栈不为空
stack.length > 0 &&
// 栈顶操作符的优先级不小于 char 的优先级
getPrecedence(stack[stack.length - 1]) >= getPrecedence(char)
) {
output.push(stack.pop());
}
stack.push(char);
}
}
// 将剩余的运算符弹出并追加到 output 后边
while (stack.length > 0) {
output.push(stack.pop());
}
return output.join('');
}
结合下图理解一下:
表达式:1 + 2 * 3 - 4
处理括号
带括号的表达式,处理逻辑和不带括号是一样的,只是多了对括号的处理。当遇到右括号时,需要把栈中左括号后面的所有运算符弹出,并追加到 output,举个例子:
计算:2 * ( 1 + 3 - 4)
通过这个例子,我们可以看出,后缀表示法居然不需要括号,更简洁。
好了,现在已经有了后序表达式,我们如何的到计算结果呢?
计算结果
计算这一步其实比较简单,直接上代码吧:
const operators = {
'+': function (a, b) { return a + b; },
'-': function (a, b) { return a - b; },
'*': function (a, b) { return a * b; },
'/': function (a, b) { return a / b; }
};
const stack = [];
postfixTokens.forEach(function (token) {
if (!isNaN(token)) {
stack.push(token);
} else if (isOperator(token)) {
var b = stack.pop();
var a = stack.pop();
stack.push(operators[token](a, b));
}
});
总结
中缀表达式对于人比较友好,而后缀表达式对计算机友好,通过对数字和运算符的编排即可实现带优先级的运算。如果本文对你有帮助,欢迎点赞、评论。
来源:juejin.cn/post/7294441582983528484