系列文章目录
前言
在之前的文章里我们已经完成了计算器的基本显示页面也实现了各个按键的点击事件,所以接下来就是对计算器的计算功能进行实现。
一、如何实现计算功能
我们想达到的效果是,在计算器上点击不同的按键来组成一个表达式,点击“=”按键时会自动在计算器显示页面上显示出结果。为了实现这个功能,我们需要借助一个算法——逆波兰表达式求值。
二、实现过程
首先,我们需要先来了解一下什么是逆波兰表达式求值。
逆波兰表达式求值是一种用于计算数学表达式的方法,也称为后缀表达式。在逆波兰表达式中,操作符跟在操作数之后,例如34+2*
代表(3+4)*2。
逆波兰表达式求值的过程是通过栈来实现的,遍历表达式的每个元素,当遇到操作数时入栈,当遇到操作符时取出栈顶的两个操作数进行运算,再将结果入栈,直到整个表达式遍历完毕。最终栈中只剩下一个元素,就是表达式的计算结果。
由此可以看到实现此算法需要借助栈这种存储结构,而所需的表达式则是我们通过点击计算器上的按键来生成的
export class Calculate {
evaluateRPN(expression: string[]): number {
const stack: number[] = [];
for (const token of expression) {
if (!isNaN(Number(token))) {
stack.push(Number(token));
} else {
const num2 = stack.pop();
const num1 = stack.pop();
switch (token) {
case "+":
stack.push(num1 + num2);
break;
case "-":
stack.push(num1 - num2);
break;
case "*":
stack.push(num1 * num2);
break;
case "/":
stack.push(num1 / num2);
break;
}
}
}
return stack.pop();
}
}
同样是把该功能的实现放在了一个单独的文件里命名为Calculate,在一开始我们先定义里一个栈来存放数据。然后创建一个临时的栈来存储我们传入的数据接着对临时栈进行遍历,如果读取的数据是number类型的数据就将此元素放入一开始定义的栈中,若不是则定义两个变量分别取出栈中的前两个元素,根据取出的符号来进行不同的计算并存入栈中。当遍历完后栈顶的元素即是我们所计算的结果,返回该元素即可。
但当我们进行测试时发现虽然实现了计算机求值的功能,但是却要求我们传入的表达式是后缀表达式。
这并不符合我们平常的输入习惯,对于计算机来说后缀表达式是便于计算机去进行计算而对于为我们来说中缀表达式是我们用的最多的,所以我们需要做的是在计算器上输入中缀表达式然后再设计一个功能将中缀表达式转换为后缀表达式来方便计算器进行计算。
export class transfer{
infixToPostfix(expression: string) {
let result: string[] = [];
let stack: string[] = [];
function precedence(operator: string): number {
if (operator === "+" || operator === "-") {
return 1;
} else if (operator === "*" || operator === "/") {
return 2;
} else {
return 0;
}
}
for (let token of expression) {
if (/[0-9]+/.test(token)) {
result.push(token);
} else {
while (stack.length !== 0 && precedence(token) <= precedence(stack[stack.length - 1])) {
result.push(stack.pop());
}
stack.push(token);
}
}
while (stack.length !== 0) {
result.push(stack.pop());
}
return result;
}
}
同样也是将该功能的实现单独的放在另一个文件里,对于该功能的实现如下:
首先,我们定义了两个数组: result
和 stack
。result
数组将用于存储后缀表达式的元素,而 stack
数组将用于存储中间计算过程中的操作符。然后定义了一个辅助函数 precedence
,用于计算给定操作符的优先级。如果操作符是 +
或 -
,则优先级为 1;如果操作符是 *
或 /
,则优先级为 2;其他情况下优先级为 0。遍历传入的表达式 ,对于每个字符如果字符是数字,将其添加到 result
数组中。如果字符是操作符,则在 stack
数组中从顶部开始依次弹出优先级大于等于当前操作符的元素,并将它们添加到 result
数组中。然后将当前操作符压入 stack
数组。循环结束后,将 stack
数组中剩余的所有元素依次弹出并添加到 result
数组中。最终返回 result
数组,即表达式的后缀表达式形式。
由此可见当我们输入中缀表达式时也可以完成计算器的计算功能了。
总结
此次文章我们采用了逆波兰表达式求值法完成了计算器的计算功能,需要注意的是再给计算机传入表达式时应该传入便于计算机计算的后缀表达式,而我们常用的时中缀表达式。因此,需要完成中缀表达式向后缀表达式的转换。至此一个完整的计算器功能已经完成了,在之后的文章里我们将会添加一些新的功能来进行项目的创新。