表達式轉表達式二叉樹

表達式樹

二叉樹是表達式處理的經常使用工具,例如,a+b*(c-d)-e/f能夠表示成以下所示的二叉樹git

其中,每一個非葉子節點表示一個運算符,左子樹是第一個運算數對應的表達式,右子樹是第二個表達式對應的表達式。每一個葉子節點都是數。數組

其在空間利用上也很是高效,節點數等於表達式的長度。工具

表達式轉二叉樹

lrj說方法有不少種,下面介紹他講的一種:找到「最後計算」的運算符(它是整個表達式樹的根),而後遞歸處理左右兩邊。ui

 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 }

前綴式、中綴式、後綴式

前綴表達式和後綴表達式分別對應表達式樹前序和後序遍歷的結果,若是不考慮括號,中綴表達式對應表達式樹中序遍歷的結果。spa

 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 //後序遍歷
10 void PostOrder(int root) 11 { 12     if (lch[root] > 0) PostOrder(lch[root]); 13     if (rch[root] > 0) PostOrder(rch[root]); 14     printf("%c ", op[root]); 15 }

表達式求值

有了表達式樹求值就很是簡單了,先求左子樹的值,再求右子樹值,而後根據根節點的運算符計算最終的值。整個過程採用遞歸求解。code

(注意!!這種方法只能求個位數表達式的值)blog

 1 //根據表達式二叉樹求值
 2 int cal(int root)  3 {  4     int ans = 0;  5     char ch = op[root];  6     if (isdigit(ch))  return ch - '0';  7     switch (ch)  8  {  9     case '+':  ans = cal(lch[root]) + cal(rch[root]); break; 10     case '-':  ans = cal(lch[root]) - cal(rch[root]); break; 11     case '*':  ans = cal(lch[root]) * cal(rch[root]); break; 12     case '/':  ans = cal(lch[root]) / cal(rch[root]); break; 13  } 14     return ans; 15 }

打印二叉樹(括號表達法)

root(lch,rch)像這樣的格式,其中lch,rch自己也是這樣的格式(遞歸定義)。整個過程相似於先序遍歷,先打印根節點,再打印左子樹,再打印右子樹。遞歸

注意格式,若是缺乏左、右子樹用空格代替(如root( ,rch)),若是都沒有,則括號也省掉。字符串

//打印表達式二叉樹
void PrintTree(int root) { int flag = 0;        //標記是否有左右子樹
    printf("%c", op[root]); if (lch[root] > 0)  flag += 1; if (rch[root] > 0)  flag += 2; if (flag == 0)  return; if (flag == 1)        //只有左子樹
 { printf("("); PrintTree(lch[root]); printf(", )"); } if (flag == 2)        //只有右子樹
 { printf("( ,"); PrintTree(rch[root]); printf(")"); } if (flag == 3)        //左右子樹都有
 { printf("("); PrintTree(lch[root]); printf(","); PrintTree(rch[root]); printf(")"); } }

 

 

最一個加一個認真寫的 胡亂寫的能實現嵌套括號、多位數相加減乘除的完整代碼string

 1 #include<stdio.h>
 2 #include<string>
 3 
 4 const int maxn = 1000 + 10;  5 char expr[maxn];        //原表達式
 6 int str[maxn];            //轉換後的表達式
 7 int lch[maxn + 1], rch[maxn + 1],op[maxn + 1];     //每一個結點的左右子結點編號和字符
 8 bool is_alpha1[maxn], is_alpha2[maxn];        //是否爲操做符或括號,前者對s數組,後者對op數組
 9 int nc = 0;         //結點數 
 10 int cnt = 0;        //轉換後字符串的長度  11 
 12 // 把表達式exp轉化成參數形式,並存到str中
 13 void analyse(char* expr)  14 {  15     int len = strlen(expr);  16     int i = 0;  17     while(i < len)  18  {  19         if (!isdigit(expr[i]))  20  {  21             str[cnt] = expr[i++];  22             is_alpha1[cnt++] = true;  23  }  24         else
 25  {  26             int tmp = 0;  27             while (isdigit(expr[i]))  28  {  29                 tmp = tmp * 10 + expr[i] - '0';  30                 i++;  31  }  32             str[cnt] = tmp;  33             is_alpha1[cnt++] = false;  34  }  35  }  36 }  37 
 38 //表達式轉表達式樹
 39 int build_tree(int* s, int x, int y)  40 {  41     int i, c1=-1, c2=-1, p=0;  42     int u;  43     if(y-x == 1)   //僅一個字符,創建單獨結點 
 44  {  45         u = ++nc;  46         lch[u] = rch[u] = 0;  47         op[u] = s[x];  48         if (is_alpha1[x])  is_alpha2[u] = true;  49         return u;  50  }  51 
 52      for (i = x; i < y; i++)   //尋找根節點的位置
 53  {  54          if(s[i] == '(' && is_alpha1[i])   p++;  55          if(s[i] == ')' && is_alpha1[i])   p--;  56          if((s[i] == '+' || s[i] == '-') && is_alpha1[i])   if (!p) c1 = i;  57          if((s[i] == '*' || s[i] == '/') && is_alpha1[i])    if (!p) c2 = i;  58  }  59     if (c1 < 0) c1 = c2;     //找不到括號外的加減號,就用乘除號 
 60     if(c1 < 0) return build_tree(s, x+1, y-1);     //整個表達式被一對括號括起來 
 61     u = ++nc;  62     lch[u] = build_tree(s, x, c1);  63     rch[u] = build_tree(s, c1+1, y);  64     op[u] = s[c1];  65     if (is_alpha1[c1])  is_alpha2[u] = true;  66     return u;  67 }  68 
 69 //先序遍歷
 70 void PreOrder(int root)  71 {  72     if(!is_alpha2[root])  printf("%d ", op[root]);  73     else  printf("%c ", op[root]);  74 
 75     if (lch[root] > 0) PreOrder(lch[root]);  76     if (rch[root] > 0) PreOrder(rch[root]);  77 }  78 
 79 //中序遍歷
 80 void InOrder(int root)  81 {  82     if (lch[root] > 0) InOrder(lch[root]);  83 
 84     if (!is_alpha2[root])  printf("%d ", op[root]);  85     else  printf("%c ", op[root]);  86 
 87     if (rch[root] > 0) InOrder(rch[root]);  88 }  89 
 90 //後序遍歷
 91 void PostOrder(int root)  92 {  93     if (lch[root] > 0) PostOrder(lch[root]);  94     if (rch[root] > 0) PostOrder(rch[root]);  95 
 96     if (!is_alpha2[root])  printf("%d ", op[root]);  97     else  printf("%c ", op[root]);  98 }  99 
100 //根據表達式二叉樹求值
101 int cal(int root) 102 { 103     int ans = 0; 104     int ch = op[root]; 105     if (!is_alpha2[root])  return ch; 106     switch (ch) 107  { 108     case '+':  ans = cal(lch[root]) + cal(rch[root]); break; 109     case '-':  ans = cal(lch[root]) - cal(rch[root]); break; 110     case '*':  ans = cal(lch[root]) * cal(rch[root]); break; 111     case '/':  ans = cal(lch[root]) / cal(rch[root]); break; 112  } 113     return ans; 114 } 115 
116 //打印表達式二叉樹
117 void PrintTree(int root) 118 { 119     int flag = 0;        //標記是否有左右子樹
120     if (!is_alpha2[root])  printf("%d", op[root]); 121     else  printf("%c", op[root]); 122 
123     if (lch[root] > 0)  flag += 1; 124     if (rch[root] > 0)  flag += 2; 125     if (flag == 0)  return; 126     if (flag == 1)        //只有左子樹
127  { 128         printf("("); 129  PrintTree(lch[root]); 130         printf(", )"); 131  } 132     if (flag == 2)        //只有右子樹
133  { 134         printf("( ,"); 135  PrintTree(rch[root]); 136         printf(")"); 137  } 138     if (flag == 3)        //左右子樹都有
139  { 140         printf("("); 141  PrintTree(lch[root]); 142         printf(","); 143  PrintTree(rch[root]); 144         printf(")"); 145  } 146 } 147 
148 int main() 149 { 150     printf("表達式:"); 151     scanf("%s", expr); 152 
153     analyse(expr);   //轉化
154 
155     
156     build_tree(str, 0, cnt);        //建樹
157 
158     int root = 1; 159     printf("先序遍歷:"); PreOrder(root); printf("\n");            //三種遍歷
160     printf("中序遍歷:"); InOrder(root); printf("\n"); 161     printf("後序遍歷:"); PostOrder(root); printf("\n"); 162 
163     printf("表達式二叉樹:"); PrintTree(root); printf("\n");        //打印表達式二叉樹
164 
165     int ans; 166     ans = cal(root);                //表達式求值
167     printf("表達式值:%d\n", ans); 168 
169     return 0; 170 }
相關文章
相關標籤/搜索