一、用二叉树表示算术表达式:
如(1+2)*(3-5)可以表示成如下图所示二叉树:
特点如下:
1、非叶子节点都是操作符;2、叶子节点是操作数。
二、如何将一个中序表达式转化成后缀表达式呢?
后缀表达式(又称逆波兰式),运算符在后,操作数在前的式子。(1+2)*(3-5)的后缀表达式就是12+35-*。可以发现表达式中没有括号了,也就是说计算机处理这个表达式的时候就不需要考虑优先级的问题了。
操作步骤:
1、首先准备一个栈opStack用于存储运算符,一个队列reversePolish用于存储逆波兰式
2、从左向右开始读取算术表达式的元素X,分以下情况进行不同的处理:
(1)如果X是操作数,直接入队(reversePolish)
(2)如果X是运算符:再分以下情况:
1)如果栈为空,直接入栈。
2)如果X==”(“,直接入栈。
3)如果X==”)“,则将栈里的元素逐个出栈,并入队到逆波兰式队列中,直到第一个配对的”)”出栈(注:“(”和“)”都不入队)
4)如果X是其他操作符,若X优先级大于栈顶元素,直接入栈。否则出栈直到X大于栈顶元素。
当读取完中序表达式后,转化好的逆波兰式就存储在队列里了。
三、计算一个逆波兰式:
首先准备一个栈s.
1、从左开始向右遍历逆波兰式的元素。
2、如果取到的元素是操作数,直接入栈s,如果是运算符,从栈中弹出2个数进行运算,然后把运算结果入栈
当遍历完逆波兰式时,计算结果就保存在栈里了。
举个栗子:12+35-*的计算过程
1、1入栈。------栈内情况:[1].
2、2入栈。------栈内情况:[1,2].
3、遇见运算符+,弹出1,2,做运算,得结果3,入栈。------栈内情况:[3].
4、3入栈。------栈内情况:[3,3].
5、5入栈。------栈内情况:[3,3,5].
6、遇见运算符-,弹出3,5,做运算,得结果-2,入栈。------栈内情况:[3,-2].
7、遇见运算符*,弹出-2,3,做运算,得结果-6,入栈。------栈内情况:[-6].
8、计算完毕,计算结果-6
四、将后缀表达式转化成二叉树:
首先准备一个二叉树节点栈s.
1、从左开始向右遍历逆波兰式的元素。
2、新建一个树节点p,值为当前元素的值。
如果取到的元素是操作数,直接把p入栈s;
如果是运算符,从栈中弹出2个节点,把第一个弹出的节点作为p的右子树,第二个弹出的节点作为p的左子树,然后把p入栈。
当遍历完逆波兰式时,树的根节点就保存在栈里了。
五、二叉树还原中序表达式
至于二叉树还原中序表达式,很容易看出对二叉树进行中序遍历即可,但是仅中序遍历时不行的,因为还没有括号。注意到二叉树的每棵子树总是要先计算的(即子树的运算优先级大于它的父节点),所以每遍历到为运算符的节点,分别加上左右括号即可保证运算优先级的正确!
六、以下是代码:
package test; import java.util.LinkedList; import java.util.Queue; import java.util.Stack; public class MathExpression { static class TreeNode { TreeNode leftChild; TreeNode rightChild; String value; } /** * 将算术表达式转化成二叉树 * * @param expression * 为了方便,使用字符串数组来存储表达式 * @return 二叉树的根节点 */ public static TreeNode createBinaryTree(String[] expression) { // 存储操作数的栈 Stack<String> opStack = new Stack<String>(); // 存储转换后的逆波兰式的队列 Queue<String> reversePolish = new LinkedList<String>(); for (String s : expression) { // 如果是数字 if(isDigit(s)){ reversePolish.offer(s); // 如果是操作符 } else if(isOperator(s)){ //是左括号直接入栈 if("(".equals(s)){ opStack.push(s); // 如果是右括号 } else if(")".equals(s)){ // 把离上一个“(”之间的操作符全部弹出来放入逆波兰式的队列中 while(!opStack.isEmpty()){ String op = opStack.peek(); if(op.equals("(")){ opStack.pop(); break; } else{ reversePolish.offer(opStack.pop()); } } } else{ while(!opStack.isEmpty()){ // 如果栈顶元素为"("直接入栈 if("(".equals(opStack.peek())){ opStack.push(s); break; //如果栈顶元素优先级大于s }else if(isGreat(opStack.peek(), s)){ reversePolish.offer(opStack.pop()); }else if(isGreat(s, opStack.peek())){ opStack.push(s); break; } } // 如果栈为空,直接入栈 if(opStack.isEmpty()) opStack.push(s); } } } // 将剩余的操作符入队 while(!opStack.isEmpty()){ reversePolish.offer(opStack.pop()); } Stack<TreeNode> nodeStack = new Stack<TreeNode>(); // 将逆波兰式转化成二叉树 while(!reversePolish.isEmpty()){ String s = reversePolish.poll(); // 以当前的元素的值新建一个节点 TreeNode node = new TreeNode(); node.value = s; // 如果是数字 if(isDigit(s)){ nodeStack.push(node); // 如果是操作符 } else if(isOperator(s)){ //从栈里弹出两个节点作为当前节点的左右子节点 TreeNode rightNode = nodeStack.pop(); TreeNode leftNode = nodeStack.pop(); node.leftChild = leftNode; node.rightChild = rightNode; // 入栈 nodeStack.push(node); } } return nodeStack.pop(); } /** * 判断是否为运算符(暂时只判断四则运算的运算符) * * @param s * @return */ static boolean isOperator(String s) { if ("(".equals(s) || ")".equals(s) || "+".equals(s) || "-".equals(s) || "*".equals(s) || "/".equals(s)) return true; else return false; } /** * 判断是否为数字 * * @param s * @return */ static boolean isDigit(String s) { for (int i = 0; i < s.length(); i++) { if (!Character.isDigit(s.charAt(i))) return false; } return true; } /** * 判断op1和op2的优先级,如果op1>op2,返回true,如果op1<=op2,返回false * * @param op1 * @param op2 * @return */ static boolean isGreat(String op1, String op2) { if (getPriority(op1) > getPriority(op2)) return true; else return false; } /** * 获取运算符的优先级 * * @param op * @return */ static int getPriority(String op) { if ("+".equals(op) || "-".equals(op)) return 1; else if ("*".equals(op) || "/".equals(op)) return 2; else throw new IllegalArgumentException("Unsupported operator!"); } /** * 打印出还原的算术表达式 * @param root */ static void printMathExpression(TreeNode root){ if(root != null){ if(isOperator(root.value)) System.out.print("("); printMathExpression(root.leftChild); System.out.print(root.value); printMathExpression(root.rightChild); if(isOperator(root.value)) System.out.print(")"); } } public static void main(String[] args) { TreeNode root = createBinaryTree(new String[]{"(", "1", "+", "2", ")", "*", "(", "3", "-", "5", ")"}); printMathExpression(root); } }