题目
编写一个程序,先用二叉树来表示一个简单算术表达式,树的每一个结点包括一个运算符或运算数。在简单算术表达式中只包含+、-、*、/
和一位正整数且格式正确**(不包括括号)**,并且要按照先乘除后加减的原则构造二叉树,图7.34所示为1+2*3-4/5
代数表达式对应的二叉树,然后由对应的二叉树计算该表达式的值。
分析
如上图所示的二叉树,就表示表达式1+2*3-4/5
,如果我们需要计算他,就需要采用前序遍历的方法。
建树
如下图所示是随便构造的一颗二叉树
他表示的是表达式:5 + 2 - 1 * 2 / 5 + 3 + 2* 3
从图中可以发现:
- 所有的叶子节点都必须是数字。
- 所有的非叶子节点都是符号,而且都必须有左子树和右子树。
- 不可能会存在一个节点仅存在左子树而不存在右子树,或者仅存在右子树而不存在左子树的情况。
+
-
节点只存在于最左边,左孩子只能是+
-
或者数字,右孩子只能是*
/
或者数字*
/
节点的右孩子只能是数字,左孩子只能是*
/
或者数字
第1 2 3条非常好理解,主要是第4条和第5条
第4条:因为我们计算的时候是采用前序遍历,前序遍历的顺序是自身、左子树、右子树,那么递归返回的顺序是右子树、左子树,乘法和除法的优先级高,所以必须要先算完乘除再算加减,所以加减号要放在左边
第5条:举个反例:
这个树表示1 / (2 * 5)
,而我们的表达式是不带括号的。
建树方法:从右往左扫描字符串,优先寻找+
-
,如果不存在+
-
则寻找*
/
,如果都不存在,说明这是一个叶子节点。一旦寻找到了符号,都会利用该符号之前的子串来递归构建左子树,右边的子串会用来递归构建右子树。
代码
#include <bits/stdc++.h>
using namespace std;
struct TreeNode{
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int v){
this->val = v;
this->left = NULL;
this->right = NULL;
}
TreeNode(char v,TreeNode* l,TreeNode *r){
this->val = v;
this->left = l;
this->right = r;
}
};
/*
string字符串转换成Int类型
*/
int stringToInt(string s){
reverse(s.begin(),s.end());
int res = 0;
for(int i = 0;i<s.size();++i){
res += (s[i]-'0') * pow(10,i);
}
return res;
}
/*
构造二叉树
*/
TreeNode* init(string s){
if(s == ""){
return NULL;
}
//首先找到+或者-
int i = s.size() - 1;
while(i>=0 && s[i] != '+' && s[i] != '-'){
--i;
}
if(i >= 0){
TreeNode* t = new TreeNode(s[i]);
t->left = init(s.substr(0,i));
t->right = init(s.substr(i+1));
return t;
}
//找不到+-就找乘除
i = s.size()-1;
while(i>=0 && s[i] != '*' && s[i] != '/'){
--i;
}
if(i >= 0){
TreeNode* t = new TreeNode(s[i]);
t->left = init(s.substr(0,i));
t->right = init(s.substr(i+1));
return t;
}
//找不到,则说明这是一个数值
TreeNode* t = new TreeNode(stringToInt(s));
return t;
}
/*
计算
*/
double calcular(TreeNode* t){
if(!t){
return 0;
}
double res = 0;
if(t->left && t->right){
//有左子树和右子树,说明当前表示一个符号
switch (t->val){
case '+':
res = calcular(t->left) + calcular(t->right);
break;
case '-':
res = calcular(t->left) - calcular(t->right);
break;
case '*':
res = calcular(t->left) * calcular(t->right);
break;
case '/':
res = calcular(t->left) * 1.0 / calcular(t->right);
break;
}
}else{
//没有左右子树(不可能会出现左子树不为空而右子树为空的情况)
res = t->val;
}
return res;
}
/*
递归销毁二叉树
*/
void destory(TreeNode* node){
if(node == NULL){
return; //已经为NULL,无需销毁
}
destory(node->left);
destory(node->right);
node->left = NULL; //销毁之后需要把指针置空
node->right = NULL;
delete node;
}
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
TreeNode* t = init("1+2*3-4/5");
cout << "1+2*3-4/5 = " << calcular(t) << endl;
TreeNode* t2 = init("1+2*3+36+10*3+25/6");
cout << "1+2*3+36+10*3+25/6 = " << calcular(t2) << endl;
destory(t);
t = NULL;
return 0;
}
如果存在什么不对的地方,欢迎指正!