————————————————————————————————————————————
實現原理:
每個操作數都被依次壓入棧中,當一個運算符到達時,從棧中彈出相應數目的操作數(對於二元運算符來說是兩個操作數),把該運算符作用於彈出的操作數,並把運算結果再壓入棧中
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
計算器(后綴表達式)
相關知識:
后綴表達式(逆波蘭表示法):在逆波蘭中,所有運算符都跟在操作數后面,如下:(1 - 2) *(4 + 5) 采用逆波蘭表示法表示為:1 2 - 4 5 + *,不需要圓括號,只要知道每個運算符需要幾個操作數就不會引起歧義
實現功能:
輸入后綴表達式,以換行結束,計算四則運算結果。
對於 1 2 - 4 5 + * 來說,首先把1和2壓入到棧中,再用兩者之差-1取代它們;然后將4和5壓入到棧中,再用兩者之和9取代它們。最后從棧中取出棧頂的-1和9,並把它們的積-9壓入到棧頂。到達輸入行的末尾時,把棧頂的值彈出來並打印。
偽代碼:
while 讀入值不為換行時
if 是數字
壓入棧中
else if 是運算符
彈出兩個運算數,計算並壓棧
else 輸入錯誤並退出
end if
讀入值
彈出最終結果並打印
實現代碼:
1 /* 實現功能:輸入后綴表達式,以換行結束,計算四則運算結果 */ 2 /* 這種后綴表示法只需要一個棧就可以了,遇到符號則彈運算數,但是中綴就不一樣 */ 3 #include <stdio.h> 4 #include <stdlib.h> 5 #define OK 1 6 #define ERROR 0 7 #define OVERFLOW -2 8 #define STACK_INIT_SIZE 100 9 #define STACKINCREAMENT 10 10 typedef int Status; 11 typedef char SElemType; 12 typedef struct 13 { 14 SElemType *top; 15 SElemType *base; 16 int stacksize; 17 } SqStack; 18 Status InitStack(SqStack *s) 19 { 20 s->base = (SElemType *)malloc(STACK_INIT_SIZE * sizeof(SElemType)); 21 if (!s->base) exit(OVERFLOW); 22 s->top = s->base; 23 s->stacksize = STACK_INIT_SIZE; 24 return OK; 25 } 26 Status Push(SqStack *s, SElemType e) 27 { 28 if (s->top - s->base == s->stacksize) 29 { 30 s->base = (SElemType *)realloc(s->base, (s->stacksize + STACKINCREAMENT) * sizeof(SElemType)); 31 if (!s->base) exit(OVERFLOW); 32 s->top = s->base + s->stacksize; 33 s->stacksize += STACKINCREAMENT; 34 } 35 s->top++; 36 *(s->top) = e; 37 return OK; 38 } 39 Status Pop(SqStack *s, SElemType *e) 40 { 41 if (s->top == s->base) exit(OVERFLOW); 42 *e = *(s->top); 43 s->top--; 44 return OK; 45 } 46 Status Empty(SqStack s) 47 { 48 if (s.top - s.base == 0) 49 return OK; 50 else 51 return ERROR; 52 } 53 int main() 54 { 55 SqStack OPND; //OPTR是運算符 OPND是運算數 56 char c, num1, num2; 57 InitStack(&OPND); 58 while((c = getchar()) != '\n') 59 { 60 switch(c) 61 { 62 case '0': 63 case '1': 64 case '2': 65 case '3': 66 case '4': 67 case '5': 68 case '6': 69 case '7': 70 case '8': 71 case '9': 72 Push(&OPND, c - '0'); 73 break; 74 case '+': 75 Pop(&OPND, &num2); 76 Pop(&OPND, &num1); 77 Push(&OPND, num1 + num2); 78 break; 79 case '-': 80 Pop(&OPND, &num2); 81 Pop(&OPND, &num1); 82 Push(&OPND, num1 - num2); 83 break; 84 case '*': 85 Pop(&OPND, &num2); 86 Pop(&OPND, &num1); 87 Push(&OPND, num1 * num2); 88 break; 89 case '/': 90 Pop(&OPND, &num2); 91 Pop(&OPND, &num1); 92 Push(&OPND, num1 / num2); 93 break; 94 default: 95 break; 96 } 97 } 98 while(!Empty(OPND)) 99 { 100 Pop(&OPND, &c); 101 printf("%d ", c); 102 } 103 return OK; 104 }
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
計算器(中綴表示法)
運算符優先級:
|
+ |
- |
* |
/ |
( |
) |
# |
+ |
> |
> |
< |
< |
< |
> |
> |
- |
> |
> |
< |
< |
< |
> |
> |
* |
> |
> |
> |
> |
< |
> |
> |
/ |
> |
> |
> |
> |
< |
> |
> |
( |
< |
< |
< |
< |
< |
= |
0 |
) |
> |
> |
> |
> |
0 |
> |
> |
# |
< |
< |
< |
< |
< |
0 |
= |
執行過程:
在計算 #4+3*(5-10)/5# 時棧中的執行過程如下
步驟 |
輸入字符 |
執行操作 |
OPTR |
OPND |
1 |
# |
Push(#) |
# |
|
2 |
4 |
Push(4) |
# |
4 |
3 |
+ |
'#'<'+',Push(+) |
# + |
4 |
4 |
3 |
Push(3) |
# + |
4 3 |
5 |
* |
'+'<'*',Push(*) |
# + * |
4 3 |
6 |
( |
'*'<'(',Push(() |
# + * ( |
4 3 |
7 |
5 |
Push(5) |
# + * ( |
4 3 5 |
8 |
- |
'('<'-',Push(-) |
# + * ( - |
4 3 5 |
9 |
10 |
Push(10) |
# + * ( - |
4 3 5 10 |
10 |
) |
'-'>')',計算並壓入結果 |
# + * ( |
4 3 -5 |
11 |
|
'('=')',脫括號 |
# + * |
4 3 -5 |
12 |
/ |
'*'>'/'計算並壓入結果 |
# + |
4 -15 |
13 |
|
'+'<'/',Push(/) |
# + / |
4 -15 |
14 |
5 |
Push(5) |
# + / |
4 -15 5 |
15 |
# |
'/'>'#',計算並壓入結果 |
# + |
4 -3 |
16 |
|
'+'>'#',計算並壓入結果 |
# |
1 |
17 |
|
'#'='#',脫括號 |
|
1 |
偽代碼:
初始化運算符棧;壓入#;
初始化運算數棧;獲取輸入;
while 獲取輸入不為#或棧頂不為#
if 輸入的是數字
壓入運算數棧
獲取輸入
if 新輸入的也是數字
十位數百位數運算
end if
else
switch 運算符棧頂與當前輸入優先級比較
壓入運算符棧
獲得輸入
彈出運算符棧頂(或#
獲得輸入
彈出運算符棧頂
彈出兩個運算數
計算並將結果壓入運算數棧
//此時不獲取新輸入,該循環輸入的運算符作為c重新進入循環
end if
end while
輸出運算數棧中剩的運算數
實現代碼:
1 /* 只能運算-128~127之間的結果 */ 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <math.h> 5 #define OK 1 6 #define ERROR 0 7 #define SPILL -2 //math.h中已有OVERFLOW,則改用SPILL 8 #define STACK_INIT_SIZE 100 9 #define STACKINCREAMENT 10 10 typedef char SElemType; 11 typedef int Status; 12 typedef struct 13 { 14 SElemType *top; 15 SElemType *base; 16 int stacksize; 17 } SqStack; 18 Status InitStack(SqStack *s) 19 { 20 s->base = (SElemType *)malloc(STACK_INIT_SIZE * sizeof(SElemType)); 21 if (!s->base) 22 exit(SPILL); 23 s->top = s->base; 24 s->stacksize = STACK_INIT_SIZE; 25 return OK; 26 } 27 Status EmptyStack(SqStack s) 28 { 29 if (s.top - s.base == 0) 30 return OK; 31 else 32 return ERROR; 33 } 34 Status Push(SqStack *s, SElemType e) 35 { 36 if (s->top - s->base == s->stacksize) 37 { 38 s->base = (SElemType *)realloc(s->base, (s->stacksize + STACKINCREAMENT) * sizeof(SElemType)); 39 if (!s->base) 40 exit(SPILL); 41 s->top = s->base + s->stacksize; 42 s->stacksize += STACKINCREAMENT; 43 } 44 s->top ++; 45 *(s->top) = e; 46 return OK; 47 } 48 Status Pop(SqStack *s, SElemType *e) 49 { 50 if (s->top == s->base) 51 exit(SPILL); 52 *e = *(s->top); 53 s->top--; 54 return OK; 55 } 56 SElemType GetTop(SqStack s) 57 { 58 return *(s.top); 59 // *e = *(s.top); 60 // return OK; 61 } 62 /* 判斷如果是數字則返回OK,運算符返回ERROR,非法輸入則退出 */ 63 Status InputJudge(SElemType c) 64 { 65 switch(c) 66 { 67 case '0': 68 case '1': 69 case '2': 70 case '3': 71 case '4': 72 case '5': 73 case '6': 74 case '7': 75 case '8': 76 case '9': 77 return OK; 78 break; 79 case '+': 80 case '-': 81 case '*': 82 case '/': 83 case '(': 84 case ')': 85 case '#': 86 return ERROR; 87 break; 88 default: 89 exit(SPILL); 90 break; 91 } 92 } 93 /* 當前輸入的運算符和前一個運算符比較優先級 */ 94 SElemType PriorityJudge(SElemType optr1, SElemType optr2) 95 { 96 int i, j; 97 char priorityTable[7][7] = 98 { 99 {'>', '>', '<', '<', '<', '>', '>'}, 100 {'>', '>', '<', '<', '<', '>', '>'}, 101 {'>', '>', '>', '>', '<', '>', '>'}, 102 {'>', '>', '>', '>', '<', '>', '>'}, 103 {'<', '<', '<', '<', '<', '=', '0'}, 104 {'>', '>', '>', '>', '0', '>', '>'}, 105 {'<', '<', '<', '<', '<', '0', '='} 106 }; 107 switch(optr1) 108 { 109 case '+': 110 i = 0; 111 break; 112 case '-': 113 i = 1; 114 break; 115 case '*': 116 i = 2; 117 break; 118 case '/': 119 i = 3; 120 break; 121 case '(': 122 i = 4; 123 break; 124 case ')': 125 i = 5; 126 break; 127 case '#': 128 i = 6; 129 break; 130 } 131 switch(optr2) 132 { 133 case '+': 134 j = 0; 135 break; 136 case '-': 137 j = 1; 138 break; 139 case '*': 140 j = 2; 141 break; 142 case '/': 143 j = 3; 144 break; 145 case '(': 146 j = 4; 147 break; 148 case ')': 149 j = 5; 150 break; 151 case '#': 152 j = 6; 153 break; 154 } 155 return priorityTable[i][j]; 156 } 157 /* 四則運算 */ 158 SElemType Calc(SElemType optr, SElemType num1, SElemType num2) 159 { 160 switch(optr) 161 { 162 case '+': 163 return (num1 + num2); 164 break; 165 case '-': 166 return (num1 - num2); 167 break; 168 case '*': 169 return (num1 * num2); 170 break; 171 case '/': 172 return (num1 / num2); 173 break; 174 } 175 } 176 int main() 177 { 178 char c, optr, num1, num2, temp; 179 SqStack OPND, OPTR; 180 InitStack(&OPTR); 181 Push(&OPTR, '#'); 182 InitStack(&OPND); 183 c = getchar(); 184 while(c != '#' || GetTop(OPTR) != '#') 185 // while(!EmptyStack(OPTR)) 186 //嚴蔚敏老師書上的算法是判斷輸入非#或棧頂非#時循環,個人認為判斷運算符棧不為空也可以,當初始化時壓入的#閉合,結束運算 187 { 188 if (InputJudge(c)) 189 { 190 Push(&OPND, c - '0'); 191 c = getchar(); 192 /* 當連續輸入數字時,計算十位數和百位數 */ 193 while(InputJudge(c)) 194 { 195 int i = 1; 196 Pop(&OPND, &temp); 197 Push(&OPND, temp * pow(10, i) + (c - '0')); 198 i++; 199 c = getchar(); 200 } 201 } 202 else 203 switch(PriorityJudge(GetTop(OPTR), c)) 204 { 205 case '<': 206 Push(&OPTR, c); 207 c = getchar(); 208 break; 209 case '=': 210 Pop(&OPTR, &c); 211 c = getchar(); 212 break; 213 case '>': 214 Pop(&OPTR, &optr); 215 Pop(&OPND, &num2); 216 Pop(&OPND, &num1); 217 Push(&OPND, Calc(optr, num1, num2)); 218 break; 219 } 220 } 221 while(!EmptyStack(OPND)) 222 { 223 Pop(&OPND, &c); 224 printf("%d\n", c); 225 } 226 return OK; 227 }