算术表达式的转换
题目描述
小明在学习了数据结构之后,突然想起了以前没有解决的算术表达式转化成后缀式的问题,今天他想解决一下。
因为有了数据结构的基础小明很快就解出了这个问题,但是他突然想到怎么求出算术表达式的前缀式和中缀式呢?小明很困惑。聪明的你帮他解决吧。
输入
输入一算术表达式,以\'#\'字符作为结束标志。(数据保证无空格,只有一组输入)
输出
输出该表达式转换所得到的前缀式 中缀式 后缀式。分三行输出,顺序是前缀式 中缀式 后缀式。
示例输入
a*b+(c-d/e)*f#
示例输出
+*ab*-c/def a*b+c-d/e*f ab*cde/-f*+
代码操作归结为:
将中缀式转化为后缀式;
将后缀式转化为表达式树;
将表达式树先序,中序,后序遍历得前缀式,中缀式,后缀式;
1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 5 struct node 6 { 7 char ch; 8 struct node *l,*r; 9 }; 10 char s[110],s1[110],s2[110]; 11 int q; 12 13 void post() 14 { 15 int x = 0, y = 0; 16 for(q = 0; s[q] != '#'; q++) 17 { 18 if(s[q] >= 'a' && s[q] <= 'z') 19 s1[x++] = s[q]; 20 else if(s[q] == '(') 21 s2[y++] = s[q]; 22 else if(s[q] == ')') 23 { 24 while(s2[y-1] != '(') 25 { 26 s1[x] = s2[y-1]; 27 x++; 28 y--; 29 } 30 y--; 31 } 32 else if(s[q] == '+' || s[q] == '-') 33 { 34 while(y != 0 && s2[y-1] != '(') 35 { 36 s1[x] = s2[y-1]; 37 x++; 38 y--; 39 } 40 s2[y++] = s[q]; 41 } 42 else if(s[q] == '*' || s[q] == '/') 43 { 44 while(y != 0 &&(s2[y-1]=='*'||s2[y-1]=='/')) 45 { 46 s1[x] = s2[y-1]; 47 x++; 48 y--; 49 } 50 s2[y++] = s[q]; 51 } 52 } 53 while(y != 0) 54 { 55 s1[x] = s2[y-1]; 56 x++; 57 y--; 58 } 59 s1[x] = '\0'; 60 } 61 void preorder(struct node *p) 62 { 63 if(p == NULL) 64 return; 65 printf("%c",p->ch); 66 preorder(p->l); 67 preorder(p->r); 68 } 69 void inorder(struct node *p) 70 { 71 if(p == NULL) 72 return; 73 inorder(p->l); 74 printf("%c",p->ch); 75 inorder(p->r); 76 } 77 void postorder(struct node *p) 78 { 79 if(p == NULL) 80 return; 81 postorder(p->l); 82 postorder(p->r); 83 printf("%c",p->ch); 84 } 85 86 int main() 87 { 88 int i,top = 0; 89 scanf("%s",s); 90 //转化为后缀式 91 post(); 92 93 //转化成表达式树(链栈) 94 struct node *po[110] = {NULL},*pi; 95 for(i = 0; i < q; i++) 96 { 97 if(s1[i] >= 'a' && s1[i] <= 'z') 98 { 99 pi = (struct node *)malloc(sizeof(struct node)); 100 pi->ch = s1[i]; 101 pi->l = NULL; 102 pi->r = NULL; 103 po[top++] = pi; 104 } 105 else 106 { 107 pi = (struct node *)malloc(sizeof(struct node)); 108 pi->ch = s1[i]; 109 pi->r = po[top-1];//注意先是右子树再是左子树 110 top--; 111 pi->l = po[top-1]; 112 top--; 113 po[top++] = pi; 114 } 115 } 116 117 //分别遍历 118 preorder(po[0]); 119 printf("\n"); 120 inorder(po[0]); 121 printf("\n"); 122 postorder(po[0]); 123 printf("\n"); 124 return 0; 125 126 }
下面来讨论如何根据表达式建立一棵树。我们知道在表达式树中,只有度为2的树杈结点与度为0的叶子节点,并且树杈节点上都存放运算符,叶子节点都存放操作数。比如由表达式1+2*3创建的树是这样的:
每一个叶子结点有一个确定的值,对于每一个运算符结点,也可以看做它代表一个值,其值为左子树的值与右子树的值按照结点中存储的运算符计算后的结果。如结点’+’的值为“1+右子树的值”,而右子树的值为它的左子树的值乘以它的右子树的值,即”2*3”,所以表达式的值就是根节点的值”1+2*3”。
由上述递归的定义不难看出,建立表达式树就是建立树中的每一个结点,将每一个结点链接起来就是整棵树。而在建立深度低的结点时要将其左右指针指向之前建立的深度比它高一级的结点(如’*’要指向’2’和’3’,而’+’又要指向’*’)。这样我们可以用栈来存放每次建立的结点,按照优先级(表达式为中缀型)或顺序扫描表达式(表达式为波兰式与逆波兰式)建立每一个结点。建立结点的顺序即为表达式求值的顺序。如果扫描到操作数则直接新建一个左右指针为空的结点,并压入结点栈中(存放结点指针)。遇到运算符时首先新建一个结点,然后从栈中依次弹出两个结点,并让新建立的结点的左右指针域指向它们。当所有结点建立完毕时,如果表达式没有错误(这里假设输入表达式正确),这时栈中应该只剩下一个结点,它就是所建立的表达式的根结点。