计算机如何计算数学表达式
平时写的1+2是中缀表达式,对应二叉树的中序遍历
计算机实际计算过程是:先将我们写的中缀表达式转成后缀表达式(二叉树的后序遍历),然后计算的。
中缀转后缀
下面是中缀转后缀的代码,用到了运算符优先级算法,
算法的基本思想:*/的优先级比±高,当前时运算符时,只要栈中的运算符的优先级>=当前运算符,则出栈
注意:表达式对应的语法树一定要画正确,否则可能导致对优先级算法的理解有误!
class Solution {
/**
* 中缀表达式转换为后缀表达式 "3*4-2*5" -> "34*25*-"
* 后缀表达式也就是逆波兰表达式。
*/
private String infixToPostfix(String s) {
StringBuilder sb = new StringBuilder();
Deque<Character> stack = new ArrayDeque<>();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
switch (c) {
case '(':
stack.addLast(c);
break;
case ')':
while (!stack.isEmpty()&&stack.peekLast()!='('){
sb.append(stack.removeLast());
}
stack.removeLast(); //(出栈
break;
case '+':
case '-':
while (!stack.isEmpty()&&stack.peekLast()!='('){
sb.append(stack.removeLast());
}
stack.addLast(c);
break;
case '*':
case '/':
while (!stack.isEmpty()&&stack.peekLast()!='('&&stack.peekLast()!='+'&&stack.peekLast()!='-'){
sb.append(stack.removeLast());
}
stack.addLast(c);
break;
default:
sb.append(c);
}
}
while (!stack.isEmpty()){
sb.append(stack.removeLast());
}
return sb.toString();
}
}
后缀表达式求值
添加链接描述
得到后缀表达式之后,就可以进行计算了,还是利用栈。
class Solution {
public int evalRPN(String[] tokens) {
Stack<Integer> stack=new Stack<>();
for (String s : tokens) {
if(s.length()>1 || Character.isDigit(s.charAt(0))){
//数字
stack.push( Integer.parseInt(s));
}else {
int num2 = stack.pop();
int num1 = stack.pop();
switch (s) {
case "+":
stack.push(num1 + num2);
break;
case "-":
stack.push(num1 - num2);
break;
case "*":
stack.push(num1 * num2);
break;
case "/":
stack.push(num1 / num2);
break;
default:
}
}
}
return stack.pop();
}
}
将中缀表达式转成抽象语法树AST
上面是模拟计算机是如何计算的,实际计算机在计算过程中,是将表达式中的每个字符封装成语法树节点,然后组装成抽象语法树,最后遍历这颗语法树求值,下面简单写下封装的逻辑代码
class Solution {
/**
* 利用后缀表达式构造AST
*/
public Node expTree(String s) {
//中缀转后缀
s=infixToPostfix(s);
//封装
Deque<Node>stack=new ArrayDeque<>();
for (int i = 0; i < s.length(); i++) {
char c=s.charAt(i);
Node node = new Node(c);
switch (c){
case '+':
case '-':
case '*':
case '/':
node.right=stack.removeLast();
node.left=stack.removeLast();
break;
default:
}
stack.addLast(node);
}
return stack.pop();
}
/**
* 中缀表达式转换为后缀表达式 "3*4-2*5" -> "34*25-"
* 后缀表达式也就是逆波兰表达式。
*/
private String infixToPostfix(String s) {
StringBuilder sb = new StringBuilder();
Deque<Character> stack = new ArrayDeque<>();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
switch (c) {
case '(':
stack.addLast(c);
break;
case ')':
while (!stack.isEmpty()&&stack.peekLast()!='('){
sb.append(stack.removeLast());
}
stack.removeLast(); //(出栈
break;
case '+':
case '-':
while (!stack.isEmpty()&&stack.peekLast()!='('){
sb.append(stack.removeLast());
}
stack.addLast(c);
break;
case '*':
case '/':
while (!stack.isEmpty()&&stack.peekLast()!='('&&stack.peekLast()!='+'&&stack.peekLast()!='-'){
sb.append(stack.removeLast());
}
stack.addLast(c);
break;
default:
sb.append(c);
}
}
while (!stack.isEmpty()){
sb.append(stack.removeLast());
}
return sb.toString();
}
}