表达式树
二叉树是表达式处理的常用工具,例如,a+b*(c-d)-e/f可以表示成如下所示的二叉树
其中,每个非叶子节点表示一个运算符,左子树是第一个运算数对应的表达式,右子树是第二个表达式对应的表达式。每个叶子节点都是数。
其在空间利用上也非常高效,节点数等于表达式的长度。
表达式转二叉树
lrj说方法有很多种,下面介绍他讲的一种:找到“最后计算”的运算符(它是整个表达式树的根),然后递归处理左右两边。
1 const int maxn = 1000 + 10;
2 char str[maxn];
3 int lch[maxn + 1], rch[maxn + 1]; char op[maxn + 1]; //每个结点的左右子结点编号和字符
4 int nc = 0; //结点数
5 int build_tree(char* s, int x, int y)
6 {
7 int i, c1=-1, c2=-1, p=0;
8 int u;
9 if(y-x == 1) //仅一个字符,建立单独结点
10 {
11 u = ++nc;
12 lch[u] = rch[u] = 0;
13 op[u] = s[x];
14 return u;
15 }
16
17 for (i = x; i < y; i++) //寻找根节点的位置
18 {
19 switch (s[i])
20 {
21 case '(': p++; break;
22 case ')': p--; break;
23 case '+':
24 case '-': if (!p) c1 = i; break;
25 case '*':
26 case '/': if (!p) c2 = i; break;
27 }
28 }
29 if (c1 < 0) c1 = c2; //找不到括号外的加减号,就用乘除号
30 if(c1 < 0) return build_tree(s, x+1, y-1); //整个表达式被一对括号括起来
31 u = ++nc;
32 lch[u] = build_tree(s, x, c1);
33 rch[u] = build_tree(s, c1+1, y);
34 op[u] = s[c1];
35 return u;
36 }
前缀式、中缀式、后缀式
前缀表达式和后缀表达式分别对应表达式树前序和后序遍历的结果,如果不考虑括号,中缀表达式对应表达式树中序遍历的结果。
1 //中序遍历
2 void InOrder(int root)
3 {
4 if (lch[root] > 0) InOrder(lch[root]);
5 printf("%c ", op[root]);
6 if (rch[root] > 0) InOrder(rch[root]);
7 }
8
9