题目:给出一个由数字及’+’,’-’,‘x’,’/’ 以及括号组成的合法算式,将其转化为表达式树。
表达式树的所有树叶都是操作数,非叶子节点都是运算符。由于给出的运算符都是二元运算符,因此这道题得到的树一定是二叉树。可以先寻找“最后计算的运算符”,将这个运算符作为一个结点,然后递归计算运算符左右两个算式,计算结果作为该节点的左右儿子。
直接上代码,需要注意的问题都写在注释里。
#include<iostream>
#include<vector>
#include<string>
#include<iomanip>
using namespace std;
string input;
struct Node //定义树的结点类型
{
int num;
char op; //每个节点要么是整型(操作数),要么是字符型(运算符)
Node* left = nullptr;
Node* right = nullptr;
};
Node* build_tree (int x, int y) //将[x,y]部分运算式转化成表达式树,并返回根
{
int p = 0; int c1 = -1; int c2 = -1; //p记录括号情况, c1记录括号外最后一个加号或者减号位置, c2记录括号外最后一个乘号或者除号位置
Node* root = new Node; //root将会保存找到的最后一个计算的运算符
for(int i = x; i <= y; i++)
{
switch(input[i])
{
case '(': p++; break;
case ')': p--; break;
case '+': case '-': if(!p) c1 = i; break; //p增加过和减少过次数一样或p没有改变过,表示在括号外,保存运算符
case '*': case '/': if(!p) c2 = i; break;
}
}
if(c1 < 0) c1 = c2; //没有找到加号减号,使用乘号或除号
if(c1 < 0) //括号外的运算符都没有,分两种情况:
{
if(input[x] == '(') return build_tree (x+1, y-1); //1.整个式子被括号括起来,去掉括号重新计算
int cur_num = 0; //2.[x,y]范围内是一个完整数字(可能是一位数也可能是多位数,如123, 需要转化成int类型并保存到cur_num
while(x <= y)
{
cur_num *= 10;
cur_num += input[x++]-'0';
}
root -> num = cur_num;
return root;
}
root -> op = input[c1];
root -> left = build_tree (x, c1 - 1); //递归计算左侧表达式
root -> right = build_tree (c1 + 1, y); //递归计算右侧表达式
return root;
}
void print_tree (Node* root, int indent) //indent表示缩进空格数目,每个节点比它的儿子节点少缩进4个空格。Inorder。
{
if (root == nullptr) return;
print_tree (root -> left, indent + 4);
if (root -> num != -1) cout << setw(indent) <<' '<< root -> num; //setw函数保存在头文件<iomanip>里
else cout << setw(indent) <<' '<< root -> op;
cout<<endl;
print_tree (root -> right, indent + 4);
}
int main ()
{
cin>>input;
int n = input.size();
Node* root = build_tree (0, n - 1); //注意build_tree(x, y)的两个参数表示闭区间[x,y]
print_tree (root, 0);
return 0;
}
输入"1+(2+3) * 4"
结果:
输入"12-(1+5) * 6+500/(2+3)-4 * 5 * 6"
结果: