最開始的計算器只能進行兩個數之間的運算,而不能進行復雜的如“9+((3*2)+(3-1))/2” 這樣的四則運算。后來一名波蘭的邏輯學家發明了后綴表達式(或稱為逆波蘭表達式),非常巧妙地解決了程序實現四則運算的難題。
后綴表達式是一種把所有運算符都放在運算數字后面出現的式子,所以被稱為后綴表達式,這樣就解決了運算優先級和括號的問題。而中綴表達式就是我們平常用的標准四則運算表達式,即“9+((3*2)+(3-1))/2”。在計算機計算一個標准四則運算表達式時,都是先將中綴表達式轉化為后綴表達式,然后進行計算。
例如中綴表達式“9+((3*2)+(3-1))/2”轉化為后綴表達式“9 3 2 * 3 1 - + 2 / +”。
中綴表達式轉化為后綴表達式規則:
1、在轉化前先建立兩個棧,暫且命名為s1和s2。用棧s1存儲后綴表達式,用棧s2存儲符號;
2、在轉化的過程中需從左到右遍歷中綴表達式的每一個數字和符號,若是數字就壓入棧s1中即成為后綴表達式的一部分;
3、若遍歷到的是符號,則判斷其與棧s2棧頂符號的優先級,若其優先級小於棧頂符號則將棧頂符號依次出棧,並依次壓入棧s1,然后將其壓入棧s2。若其是右括號則將棧頂符號依次出棧並壓入棧s1,直至遇到左括號並將左括號出棧,但不再壓入棧s1;
4、若最后棧s2中還有符號,則將其依次出棧,並壓入棧s1。最終完成轉化過程。
中綴表達式轉化為后綴表達式:
以中綴表達式“9+((3*2)+(3-1))/2”的轉化為例介紹棧s1和棧s2的情況:
注:數字和符號的順序是按在棧中的順序排列的。
(1)遍歷到字符“9”時:
棧s1:9 ;
棧s2:空 ;
(1)遍歷到符號“+”時:
棧s1:9 ;
棧s2:+ ;
(1)遍歷到符號“(”時:
棧s1:9 ;
棧s2:( + ;
(2)遍歷到符號“(”時:
棧s1:9 ;
棧s2:( ( + ;
(3)遍歷到字符“3”時:
棧s1:3 9 ;
棧s2:( ( +;
(4)遍歷到符號“*”時:
棧s1:3 9 ;
棧s2:* ( ( + ;
(5)遍歷到字符“2”時:
棧s1:2 3 9 ;
棧s2:* ( ( + ;
(6)遍歷到符號“)”時:
棧s1:2 3 9 ;
棧s2:* ( ( + ;
此時開始比較,比較之后:
棧s1:* 2 3 9 ;
棧s2:( + ;
(7)遍歷到符號“+”時:
棧s1:* 2 3 9 ;
棧s2:+ ( +;
(8)遍歷到符號“(”時:
棧s1:* 2 3 9 ;
棧s2:( + ( + ;
(9)遍歷到字符“3”時:
棧s1:3 * 2 3 9 ;
棧s2:( + ( + ;
(10)遍歷到符號“-”時:
棧s1:3 * 2 3 9 ;
棧s2:- ( + ( + ;
(11)遍歷到字符“1”時:
棧s1:1 3 * 2 3 9 ;
棧s2:- ( + ( + ;
(12)遍歷到符號“)”時:
棧s1:1 3 * 2 3 9 ;
棧s2:- ( + ( + ;
此時開始比較,比較之后:
棧s1:- 1 3 * 2 3 9 ;
棧s2:+ ( +;
(13)遍歷到符號“)”時:
棧s1:- 1 3 * 2 3 9 ;
棧s2:+ ( +;
此時開始比較,比較之后:
棧s1:+ - 1 3 * 2 3 9 ;
棧s2:+;
(14)遍歷到符號“/”時:
棧s1:+ - 1 3 * 2 3 9 ;
棧s2:/ + ;
(15)遍歷到字符“2”時:
棧s1:2 + - 1 3 * 2 3 9 ;
棧s2:/ + ;
(16)遍歷結束,但棧s2中還有符號,所以將棧s2中的符號全部依次壓入棧s1中,此時:
棧s1:+ / 2 + - 1 3 * 2 3 9 ;
棧s2:空;
所以后綴表達式為:9 3 2 * 3 1 - + 2 / + ;
后綴表達式計算結果規則:
從左到右遍歷整個后綴表達式的每一個數字和字符,遇到符號就將處於該符號前的兩個數字做當前符號的運算,然后用結果代替原來的兩個數字,一直到最終獲得結果(棧頂元素即為結果)。
1 #include<stdio.h> 2 #include<ctype.h> 3 4 typedef struct node{ 5 char ch; 6 struct node *next; 7 }*LinkList; 8 typedef struct Node{ 9 int num; 10 struct Node *Next; 11 }*Linklist; 12 13 int cmp(char c1, char c2); 14 int counter(int a, int b, char c); 15 16 int main() 17 { 18 int i, flag=0, logo; 19 char str[30]; 20 Linklist Head = new Node, pre, L = new Node; 21 LinkList head = new node, pot, p, q; 22 Head->Next = NULL; 23 L->num = 0; 24 head->ch = '#'; 25 head->next = NULL; 26 gets(str); 27 for(i = 0; ; i++){ 28 if(isdigit(str[i])){ 29 logo = 1; 30 L->num = L->num * 10 + str[i] - '0'; 31 } 32 else{ 33 if(logo){ 34 L->Next = Head->Next; 35 Head->Next = L; 36 if('\0' == str[i])/*當對到讀到'\0'時結束遍歷,在這結束時為了將最后一個數字壓入棧頂*/ 37 break; 38 L = new Node; 39 logo = L->num = 0; 40 } 41 if(head->next != NULL) 42 flag = cmp(head->next->ch, str[i]); 43 else 44 flag = cmp(head->ch, str[i]); 45 if(flag){ 46 while(head->next){ 47 pot = head->next; 48 if('(' != pot->ch){ 49 pre = Head->Next; 50 pre->Next->num = counter(pre->Next->num, pre->num, pot->ch); 51 Head->Next = pre->Next; 52 delete pre; 53 head->next = pot->next; 54 delete pot; 55 } 56 else if('(' == pot->ch){ 57 if(1 == flag) 58 pot->ch = str[i]; 59 else{ 60 head->next = pot->next; 61 delete pot; 62 } 63 break; 64 } 65 } 66 if(!head->next){ 67 p = new node; 68 p->ch = str[i]; 69 p->next = head->next; 70 head->next = p; 71 } 72 } 73 else{ 74 p = new node; 75 p->ch = str[i]; 76 p->next = head->next; 77 head->next = p; 78 } 79 } 80 } 81 while(head->next){ 82 pot = head->next; 83 pre = Head->Next; 84 pre->Next->num = counter(pre->Next->num, pre->num, pot->ch); 85 Head->Next = pre->Next; 86 delete pre; 87 head->next = pot->next; 88 delete pot; 89 } 90 printf("%d\n", Head->Next->num); 91 return 0; 92 } 93 94 int cmp(char c1, char c2) 95 { 96 if('#' == c1) 97 return 0; 98 if(')' == c2) 99 return 2; 100 if('(' == c2) 101 return 0; 102 if('*' == c2 || '/' == c2) 103 return 0; 104 if('+' == c2 || '-' == c2){ 105 if('*' == c1 || '/' == c1) 106 return 1; 107 return 0; 108 } 109 } 110 111 int counter(int a, int b, char c) 112 { 113 switch(c){ 114 case '+': 115 return a+b; 116 case '-': 117 return a-b; 118 case '*': 119 return a*b; 120 case '/': 121 return a/b; 122 } 123 }