中轉后 具體轉換方式:
1.從左到右遍歷需要計算的字符串
2.若是運算數,直接壓入后綴表達式棧
3.若是左括號,直接壓入運算符棧,(括號是最高優先級,無需比較)(入棧后優先級降到最低,確保其他符號正常入棧)
4.若是右括號,(意味着括號已結束)不斷彈出運算符棧頂運算符並輸出到后綴表達式棧
直到遇到左括號(彈出但不輸出)
5.運算符,將該運算符與運算符棧頂運算符進行比較,
如果優先級高於棧頂運算符則壓入運算符棧(該部分運算還不能進行),
如果優先級低於等於棧頂運算符則將棧頂運算符彈出到后綴表達式棧然后比較新的棧頂運算符.
(低於彈出意味着前面部分可以運算,先輸出到后綴表達式棧一定是高優先級運算符,
等於彈出是因為同等優先級,從左到右運算)
直到優先級大於棧頂運算符或者棧空,再將該運算符入運算符棧
6.如果字符串處理完畢,則按順序從運算符棧彈出所有運算符到后綴表達式棧
使用后綴表達式計算的方法:
1、 按順序取后綴表達式的每個值
2、 若是數字 則入棧
3、 若是操作符 則從棧取出兩個數字 進行運算 運算之后再將結果入棧
4、 循環上述過程知道后綴表達式結束 棧頂元素(棧中只有一個元素)即為結果
1 #include <windows.h> 2 #include <stdio.h> 3 #include <string.h> 4 #include <malloc.h> 5 #define NUM 0 6 #define OPERATION 1 7 typedef struct {//棧中的結點 8 int val; 9 int type; 10 } Node; 11 typedef struct {//棧 12 const char* name;//棧名 13 Node* sta;//結點 14 int size;//最多存儲多少個元素 15 int cnt;//當前存儲了多少個元素 16 } MyStack; 17 void trace(MyStack* s)//棧的遍歷 18 { 19 int i; 20 printf("%s棧中的元素為:", s->name); 21 for (i = 0; i < s->cnt; i++) { 22 if (s->sta[i].type == NUM) {//若是數字 23 printf("%d ", s->sta[i].val); 24 } 25 else {//若是字符 26 printf("%c ", (char)s->sta[i].val); 27 } 28 } 29 printf("\n"); 30 } 31 void sFree(MyStack* s)//釋放棧 32 { 33 if (s->sta != NULL) { 34 free(s->sta); 35 s->sta = NULL; 36 } 37 return; 38 } 39 int sInit(MyStack* s, const char* name, int size)//初始化棧 40 { 41 s->name = name; 42 s->size = size; 43 s->sta = (Node*)calloc(s->size, sizeof(Node));//calloc申請后 其中存的都是0 44 if (s->sta == NULL) { 45 return -1;//分配失敗 46 } 47 s->cnt = 0;//當前棧中元素有0個 48 return 0;//分配成功 49 } 50 void sPush(MyStack* s, Node item)//入棧一個元素 51 { 52 if (s->cnt == s->size) { 53 printf("棧空間不足\n"); 54 return; 55 } 56 s->sta[s->cnt] = item; 57 s->cnt++; 58 return; 59 } 60 bool sIsEmpty(MyStack* s)//判斷棧是否為空 61 { 62 return s->cnt == 0; 63 } 64 void sPop(MyStack* s, Node* item)//刪除棧頂元素 並返回值到item 65 { 66 if (sIsEmpty(s)) { 67 return; 68 } 69 *item = s->sta[s->cnt - 1]; 70 s->cnt--; 71 return; 72 } 73 void sTop(MyStack* s, Node* item)//獲得棧頂元素到item 不刪除棧頂袁術 74 { 75 if (sIsEmpty(s)) { 76 return; 77 } 78 *item = s->sta[s->cnt - 1]; 79 return; 80 } 81 bool myIsNum(char ch)//判斷是否是數字 82 { 83 return ch >= '0' && ch <= '9'; 84 } 85 bool myIsOper(char ch)//判斷是否是運算符 86 { 87 return ch == '+' || ch == '-' || ch == '*' || ch == '/'||ch=='('||ch==')'; 88 } 89 //處理數值 90 void procNum(MyStack* postfix_expression, char* s, int len, int* pi) 91 { 92 int i = *pi;//令i等於當前在處理的元素的坐標 93 int num=0;//當前數字的值 具體是多少 94 Node item_num; 95 while (myIsNum(s[i])) 96 { 97 num = num * 10 + s[i]-'0'; 98 i++; 99 } 100 //新建結點 101 item_num.type = NUM; 102 item_num.val = num; 103 //數字直接入后綴表達式的棧 104 sPush(postfix_expression, item_num); 105 *pi = i-1;//改變calculate_postfix_expression 中i的值 106 return; 107 } 108 //處理運算符 109 void procOper(MyStack* postfix_expression, MyStack* s_oper, char* s, int len, int* pi) 110 { 111 int i = *pi; 112 Node item; 113 Node top_item; 114 Node pop_item; 115 if (s[i] == '(')//如果是( 直接存入運算符棧 116 { 117 item.type = OPERATION; 118 item.val = s[i]; 119 sPush(s_oper, item); 120 } 121 else if (s[i] == ')')//若是) 則彈出到(為止 122 { 123 int flag = 0;//是否找到了 ( 124 while (!sIsEmpty(s_oper)) { 125 sPop(s_oper, &pop_item); 126 if (pop_item.val == '(') {//若找到了左括號退出 127 flag = 1; 128 break; 129 } 130 sPush(postfix_expression, pop_item);//若未找到左括號 則一直從運算符棧中pop 131 } 132 if (!flag) 133 { 134 printf("括號不匹配!"); 135 exit(0); 136 } 137 } 138 //如果是乘除 139 else if (s[i] == '*' || s[i] == '/') 140 { 141 item.type = OPERATION; 142 item.val = s[i]; 143 while (!sIsEmpty(s_oper)) { 144 sTop(s_oper, &top_item); 145 //如果當前運算符棧的棧頂是+ - ( 146 //則* /級別較高 則跳出循環 147 if (top_item.val == '+' || top_item.val == '-' || top_item.val == '(') { 148 break; 149 } 150 //若當前運算符棧頂不是+ - ( 則是* / 151 //則需先把* / pop完 152 sPop(s_oper, &pop_item); 153 sPush(postfix_expression, pop_item); 154 } 155 //才能將當* /入棧 156 sPush(s_oper, item); 157 } 158 //如果是 + - 159 else if (s[i] == '+' || s[i] == '-') 160 { 161 item.type = OPERATION; 162 item.val = s[i]; 163 while (!sIsEmpty(s_oper)) { 164 sTop(s_oper, &top_item); 165 //如果當前運算符棧的棧頂是 ( 166 //則當前運算符級別較高 則跳出循環 167 if (top_item.val == '(') { 168 break; 169 } 170 //若當前運算符棧頂不是 ( 則是+ - * / 171 //則需先把+ - * /pop完 172 sPop(s_oper, &pop_item); 173 sPush(postfix_expression, pop_item); 174 } 175 //才能將當+ - 入棧 176 sPush(s_oper, item); 177 } 178 else 179 { 180 printf("輸入了非空格 非數字 非運算符的元素 %c\n", s[i]); 181 exit(0); 182 } 183 return; 184 } 185 //計算后綴表達式 存儲在s_trans中 186 void calculate_postfix_expression(MyStack* postfix_expression, MyStack* s_oper, char* s, int len) 187 { 188 int i; 189 int ret; 190 int num; 191 Node item; 192 for (i = 0; i < len; i++) { 193 if (s[i] == ' ') {//當前輸入為空格時 跳過 194 continue; 195 } 196 if (myIsNum(s[i])) {//當前是數字時 197 procNum(postfix_expression, s, len, &i); 198 continue; 199 } 200 if (myIsOper(s[i])) {//當前是運算符時 進入運算的處理程序 201 procOper(postfix_expression, s_oper, s, len, &i); 202 continue; 203 } 204 printf("輸入了非空格 非數字 非運算符的元素 %c\n", s[i]); 205 exit(0); 206 } 207 //若運算棧不為空 依次pop出運算棧中的元素 再push到后綴表達式棧 208 while (!sIsEmpty(s_oper)) { 209 sPop(s_oper, &item); 210 sPush(postfix_expression, item); 211 } 212 return; 213 } 214 int cal(MyStack* postfix_expression, MyStack* s_num)//進行計算 215 { 216 int i; 217 Node n1, n2; 218 Node item; 219 //順序取出棧中的每個元素 220 for (i = 0; i < postfix_expression->cnt; i++) { 221 //item為后綴表達式中順序取的第i個元素 222 item = postfix_expression->sta[i]; 223 //若一直是數字 則一直放進數字棧 224 if (item.type == NUM) { 225 sPush(s_num, item); 226 continue;//開始下一次循環 227 } 228 //執行到這里證明不是數字 是運算符了 229 sPop(s_num, &n2);//從棧中拿出兩個元素到n2 n1中 230 sPop(s_num, &n1); 231 if (item.val == '+') { 232 n1.val += n2.val; 233 } 234 else if (item.val == '-') { 235 n1.val -= n2.val; 236 } 237 else if (item.val == '*') { 238 n1.val *= n2.val; 239 } 240 else { 241 n1.val /= n2.val; 242 } 243 sPush(s_num, n1);//再將此次運算結果入數字棧 244 } 245 return s_num->sta[0].val;//最后數字棧中的第一個元素就是 計算結果 246 } 247 int calculate(char* s) {//進行計算 248 int ret; 249 int len; 250 if (s == NULL||(len=strlen(s))==0) { 251 return 0; 252 } 253 MyStack s_num;//數字棧 254 MyStack s_oper;//運算符棧 255 MyStack postfix_expression;//后綴表達式棧 256 if (sInit(&s_num, "數字", len)==-1|| 257 sInit(&s_oper, "運算符", len)==-1|| 258 sInit(&postfix_expression, "后綴表達式", len)==-1 259 ) //若初始化三個棧失敗的話 則釋放內存 return 0 260 { 261 sFree(&s_num); 262 sFree(&postfix_expression); 263 sFree(&s_oper); 264 return 0; 265 } 266 //計算后綴表達式 267 calculate_postfix_expression(&postfix_expression, &s_oper, s, len); 268 //顯示后綴表達式 269 trace(&postfix_expression); 270 //使用后綴表達是進行計算 271 ret = cal(&postfix_expression, &s_num); 272 //釋放棧的空間 273 sFree(&postfix_expression); 274 sFree(&s_oper); 275 sFree(&s_num); 276 //返回結果 277 return ret; 278 } 279 int main() 280 { 281 char str[10000]; 282 scanf("%[^\n]", str);//可以輸入空格 回車停止輸入 283 printf("計算結果為%d\n", calculate(str)); 284 } 285 //例子 (((50+20)+(2*3))/14)
