简单算术表达式(无括号)
使用二叉树的构建和求值
题目:
编写一个程序,先用二叉树来表示一个简单算术表达式,树的每一个结点包括一个运算符或运算数。在简单算术表达式中只包含+、-、*、/
和一位正整数且格式正确**(不包括括号)**,并且要按照先乘除后加减的原则构造二叉树
分析:
表示的是表达式:5 + 2 - 1 * 2 / 5 + 3 + 2* 3
从图中可以发现:
1、所有的叶子节点都必须是数字。
2、所有的非叶子节点都是符号,而且都必须有左子树和右子树。
3、不可能会存在一个节点仅存在左子树而不存在右子树,或者仅存在右子树而不存在左子树的情况。
4、+
-
节点只存在于最左边,左孩子只能是+
-
或者数字,右孩子只能是*
/
或者数字
5、+
/
节点的右孩子只能是数字,左孩子只能是*
/
或者数字
因为我们计算的时候是采用前序遍历,前序遍历的顺序是自身、左子树、右子树,那么递归返回的顺序是右子树、左子树,乘法和除法的优先级高,所以必须要先算完乘除再算加减,所以加减号要放在左边
源码:
static class BTNode {
int value;
BTNode leftChild, rightChild;
public BTNode(int value) {
this.value = value;
leftChild = null;
rightChild = null;
}
public BTNode(char value, BTNode leftChild, BTNode rightChild) {
this.value = value;
this.leftChild = leftChild;
this.rightChild = rightChild;
}
}
/**
* 将字符串str转换成int
*
* @param str
* @return int
*/
public static int stringToInt(String str) {
/*str = new StringBuilder(str).reverse().toString(); //反转字符串
int result = 0;
for (int i = 0; i < str.length(); i++) {
result += (int) (str.charAt(i) * Math.pow(10, i));
}*/
int result = 0;
for (int i = str.length() - 1; i >= 0; i--){
result += (str.charAt(i) - '0') * Math.pow(10, str.length() - i - 1);
}
return result;
}
/**
* 构造二叉树
*
* @param str
* @return BTNode
*/
public static BTNode initBTree(String str) {
if (str == "") return null;
//首先找+-
int index = str.length() - 1;
while (index >= 0 && str.charAt(index) != '+' && str.charAt(index) != '-')
--index;
if (index >= 0) {
BTNode node = new BTNode(str.charAt(index),
initBTree(str.substring(0, index)),
initBTree(str.substring(index + 1)));
return node;
}
//找不到+-就找*/
index = str.length() - 1;
while (index >= 0 && str.charAt(index) != '*' && str.charAt(index) != '/')
--index;
if (index >= 0) {
BTNode node = new BTNode(str.charAt(index),
initBTree(str.substring(0, index)),
initBTree(str.substring(index + 1)));
return node;
}
//都找不到,说明是一个数值
BTNode node = new BTNode(stringToInt(str));
return node;
}
/**
* 计算算术表达式的值
*
* @param tree
* @return double
*/
public static double calculate(BTNode tree) {
if (tree == null) return 0;
double result = 0;
if (tree.leftChild != null && tree.rightChild != null) {
//有左右子树表示当前结点是一个字符
switch (tree.value) {
case '+':
result = calculate(tree.leftChild) + calculate(tree.rightChild);
break;
case '-':
result = calculate(tree.leftChild) - calculate(tree.rightChild);
break;
case '*':
result = calculate(tree.leftChild) * calculate(tree.rightChild);
break;
case '/':
result = calculate(tree.leftChild) * 1.0 / calculate(tree.rightChild);
break;
}
} else result = tree.value; //没有左右子树说明该结点是叶子结点,即数值结点
return result;
}
public static void main(String[] args) {
BTNode tree = initBTree("1+2*3-4/5");
double res = calculate(tree);
System.out.println("1+2*3-4/5=" + String.format("%.2f", res)); //保留两位小数
tree = initBTree("1+2*3+36+10*3+25/6");
res = calculate(tree);
System.out.println("1+2*3+36+10*3+25/6=" + String.format("%.2f", res));//保留两位小数
}