對於用低級編程語言是實現對運算式的處理,后綴式(逆波蘭式)最為簡便。下面是將中綴式(常見運算式)轉換為后綴式的算法:
棧底放‘#’,從左至右逐字讀取中綴式:
a.當當前字符為數字時,直接輸出;
b.當當前字符為"("時,將其壓棧;
c.當當前字符為")"時,則彈出堆棧中最上的"("之前的所有運算符並輸出,然后刪除堆棧中的"(" ;
d.當當前字符為運算符時,則依次彈出堆棧中優先級大於等於當前運算符的(到"("之前為止),輸出,再將當前運算符壓棧;
e.當為"#"時,彈出所有棧中的內容輸出
中綴式:a*(b+c)/d+e
后綴式:abc+*d/e+
應用實例:
算術表達式的轉換
Time Limit: 1000MS Memory limit: 65536K
題目描述
小明在學習了數據結構之后,突然想起了以前沒有解決的算術表達式轉化成后綴式的問題,今天他想解決一下。
因為有了數據結構的基礎小明很快就解出了這個問題,但是他突然想到怎么求出算術表達式的前綴式和中綴式呢?小明很困惑。聰明的你幫他解決吧。
輸入
輸入一算術表達式,以\'#\'字符作為結束標志。(數據保證無空格,只有一組輸入)
輸出
輸出該表達式轉換所得到的前綴式 中綴式 后綴式。分三行輸出,順序是前綴式 中綴式 后綴式。
示例輸入
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 struct node 5 { 6 int data; 7 struct node *l; 8 struct node *r; 9 }; 10 char s[101],q1[101],q2[101]; 11 int sp(char ch) 12 { 13 int x; 14 switch(ch) 15 { 16 case '+':x=1;break; 17 case '-':x=1;break; 18 case '*':x=2;break; 19 case '/':x=2;break; 20 default :x=0; 21 } 22 return x; 23 } 24 int i; 25 void change()//將中綴式化為后綴式函數 26 { 27 28 int x=0,y=0; 29 for(i=0; s[i]!='#'; i++) 30 { 31 if(s[i]>='a'&&s[i]<='z') 32 q1[x++]=s[i]; 33 else if(s[i]=='(') 34 q2[y++]=s[i]; 35 else if(s[i]==')') 36 { 37 while(q2[y-1]!='(') 38 { 39 q1[x]=q2[y-1]; 40 x++; 41 y--; 42 } 43 y--; 44 } 45 else if(sp(s[i])==1) 46 { 47 while(y!=0&&q2[y-1]!='(') 48 { 49 q1[x]=q2[y-1]; 50 x++; 51 y--; 52 } 53 q2[y++]=s[i]; 54 } 55 else if(sp(s[i])==2) 56 { 57 while(y!=0&&sp(q2[y-1])==2) 58 { 59 q1[x]=q2[y-1]; 60 x++; 61 y--; 62 } 63 q2[y++]=s[i]; 64 } 65 66 } 67 while(y!=0) 68 { 69 q1[x]=q2[y-1]; 70 x++; 71 y--; 72 } 73 q1[x]='\0'; 74 75 } 76 void pretree(struct node *p)//前序遍歷 77 { 78 if(p != NULL) 79 { 80 printf("%c",p->data); 81 pretree(p->l); 82 pretree(p->r); 83 } 84 } 85 void intree(struct node *p)//中序遍歷 86 { 87 if(p != NULL) 88 { 89 intree(p->l); 90 printf("%c",p->data); 91 intree(p->r); 92 93 } 94 } 95 int main() 96 { 97 int top=0,j; 98 gets(s); 99 change(); //將中綴式化為后綴式 100 struct node *tree[101]= {NULL},*pi; //建立表達式樹,用鏈棧 101 for( j = 0; j < i; j++) 102 { 103 if(q1[j] >= 'a' && q1[j] <= 'z') 104 { 105 pi = (struct node *)malloc(sizeof(struct node)); 106 pi->data = q1[j]; 107 pi->l = NULL; 108 pi->r = NULL; 109 tree[top++] = pi; 110 } 111 else 112 { 113 pi = (struct node *)malloc(sizeof(struct node)); 114 pi->data = q1[j]; 115 pi->r = tree[top-1]; 116 top--; 117 pi->l = tree[top-1]; 118 top--; 119 tree[top++] = pi; 120 } 121 } 122 pretree(tree[0]); 123 printf("\n"); 124 intree(tree[0]); 125 printf("\n"); 126 puts(q1); //這里可換為后序遍歷 127 return 0; 128 }
代碼操作歸結為:
將中綴式轉化為后綴式;
將后綴式轉化為表達式樹;
將表達式樹先序,中序,后序遍歷得前綴式,中綴式,后綴式;
如何根據表達式建立一棵樹:
我們知道在表達式樹中,只有度為2的樹杈結點與度為0的葉子節點,並且樹杈節點上都存放運算符,葉子節點都存放操作數。比如由表達式1+2*3創建的樹是這樣的:
每一個葉子結點有一個確定的值,對於每一個運算符結點,也可以看做它代表一個值,其值為左子樹的值與右子樹的值按照結點中存儲的運算符計算后的結果。如結點
’+’的值為“1+右子樹的值”,而右子樹的值為它的左子樹的值乘以它的右子樹的值,即”2*3”,所以表達式的值就是根節點的值”1+2*3”。
由上述遞歸的定義不難看出,建立表達式樹就是建立樹中的每一個結點,將每一個結點鏈接起來就是整棵樹。而在建立深度低的結點時要將其左右指針指向之前建立的深度比它高一級的結點
(如’*’要指向’2’和’3’,而’+’又要指向’*’)。這樣我們可以用棧來存放每次建立的結點,按照優先級(表達式為中綴型)或順序掃描表達式(表達式為波蘭式與逆波蘭式)建立每一個結點。建立結點的順序即為表達式求值的順序。如果掃描到操作數則直接新建一個左右指針為空的結點,並壓入結點棧中(存放結點指針)。遇到運算符時首先新建一個結點,然后從棧中依次彈出兩個結點,並讓新建立的結點的左右指針域指向它們。當所有結點建立完畢時,如果表達式沒有錯誤(這里假設輸入表達式正確),這時棧中應該只剩下一個結點,它就是所建立的表達式的根結點。