c語言表達式求值 中綴表達式轉后綴表達式 求值


中轉后 具體轉換方式:

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)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM