逆波蘭表達式——中綴表達式轉后綴表達式


逆波蘭表達式

先說一下中綴表達式,平時我們使用的運算表達式就是中綴表達式,例如1+3*2,中綴表達式的特點就是:二元運算符總是置於與之相關的兩個運算對象之間

人讀起來比較好理解,但是計算機處理起來就很麻煩,運算順序往往因表達式的內容而定,不具規律性

 

后綴表達式,后綴表達式的特點就是:每一運算符都置於其運算對象之后,以上面的中綴表達式1+2*3為例子,轉為后綴表達式就是123*+

 

下面先分析怎么把中綴表達式轉換為后綴表達式,這里我們考慮六種操作符'+'、'-'、'*'、'/'、'('、')',完成中綴轉后綴我們需要兩個數組,都以棧的方式來操作,一個數組用來存放后綴表達式(char num[100]),

一個數組用來臨時存放操作數(char opera[100])(這里說臨時存放,是因為最后都要入棧到后綴表達式數組num中,這個數組就相當於一個中轉站)

 

1、從左往右掃描中綴表達式(這里我們以1*(2+3)為例)

 

2、如果是數字那么將其直接入棧到數組num

3、如果是操作數,需要進一步判斷

(1)如果是左括號'('直接入棧到數組opera

(2)如果是運算符('+'、'-'、'*'、'/'),先判斷數組opera棧頂的操作數的優先級(如果是空棧那么直接入棧到數組opera),如果是左括號那么直接入棧到數組opera中,如果棧頂是運算符,且棧頂運算符的優先級大於該運算符

那么將棧頂的運算符出棧,並入棧到數組num中,重復步驟3,如果棧頂運算符優先級小於該運算符,那么直接將該運算符入棧到opera中

(3)如果是右括號')',那么說明在opera數組中一定有一個左括號與之對應(在你沒輸錯的情況下),那么將opera中的運算符依次出棧,並入棧到num中,直到遇到左括號'('(注意左括號不用入棧到num

4、如果中綴表達式掃描完了,那么將opera中的操作數依次出棧,並入棧到num中就可以了,如果沒有沒有掃描完重復1-3步

上面就是中綴表達式轉后綴表達式的步驟了,下面用圖來直觀的了解一下這個過程

 

需要注意的是:opera中操作數,越靠近棧頂,優先級越高,下面附上實現代碼

  1 void PexpretoSexpre(char *ss)
  2 {
  3     char num[100] = "0";    /* 存儲后綴表達式 */
  4     char opera[100] = "0";    /* 存儲運算符 */
  5     /*
  6     num----j
  7     opera----op
  8     ss----i
  9     */
 10     int i, j, op;
 11 
 12     op = i = j = 0;
 13 
 14     while (ss[i] != '\0')
 15     {
 16         if (isdigit(ss[i]))    /* 如果是數字 */
 17         {
 18             num[j] = ss[i];    /* 數字直接入后綴表達式棧 */
 19             j++;
 20             i++;
 21         }
 22         else
 23         {
 24             switch (ss[i])    /* 如果是操作數 */
 25             {
 26             case '+':
 27                 {
 28                     if (op == 0)    /* 如果是空棧 */
 29                     {
 30                         PushOperation(opera, ss, &op, &i);    /* 入運算符棧 */
 31                         break;
 32                     }
 33                     if (opera[op-1] == '+' || opera[op-1] == '-' || opera[op-1] == '*' || opera[op-1] == '/' || opera[op-1] == ')' || opera[op-1] == '(')
 34                     {
 35                         switch (opera[op-1])
 36                         {
 37                         case '+':
 38                             {
 39                                 PushOperation(opera, ss, &op, &i);
 40                                 break;
 41                             }
 42                         case '-':
 43                             {
 44                                 PushOperation(opera, ss, &op, &i);
 45                                 break;
 46                             }
 47                         case '*':
 48                             {    /* 加法優先級低於乘法 */
 49                                 num[j] = opera[op-1];    /* 將操作數出棧 */
 50                                 opera[op-1] = ss[i];        /* 將新的操作數壓入棧中 */
 51                                 j++;
 52                                 i++;
 53                                 break;
 54                             }
 55                         case '/':
 56                             {
 57                                 num[j] = opera[op-1];
 58                                 opera[op-1] = ss[i];
 59                                 j++;
 60                                 i++;
 61                                 break;
 62                             }
 63                         case '(':
 64                             {
 65                                 PushOperation(opera, ss, &op, &i);
 66                                 break;
 67                             }
 68                         }
 69                     }
 70                     break;
 71                 }
 72             case '-':
 73                 {
 74                     if (op == 0)
 75                     {
 76                         PushOperation(opera, ss, &op, &i);
 77                         break;
 78                     }
 79                     if (opera[op-1] == '+' || opera[op-1] == '-' || opera[op-1] == '*' || opera[op-1] == '/' || opera[op-1] == ')' || opera[op-1] == '(')
 80                     {
 81                         switch (opera[op-1])
 82                         {
 83                         case '+':
 84                             {
 85                                 PushOperation(opera, ss, &op, &i);
 86                                 break;
 87                             }
 88                         case '-':
 89                             {
 90                                 PushOperation(opera, ss, &op, &i);
 91                                 break;
 92                             }
 93                         case '*':
 94                             {
 95                                 num[j] = opera[op-1];
 96                                 opera[op-1] = ss[i];
 97                                 j++;
 98                                 i++;
 99                                 break;
100                             }
101                         case '/':
102                             {
103                                 num[j] = opera[op-1];
104                                 opera[op-1] = ss[i];
105                                 j++;
106                                 i++;
107                                 break;
108                             }
109                         case '(':
110                             {
111                                 PushOperation(opera, ss, &op, &i);
112                                 break;
113                             }
114                         }
115                     }
116                     break;
117                 }
118             case '*':
119                 {
120                     if (op == 0)
121                     {
122                         PushOperation(opera, ss, &op, &i);
123                         break;
124                     }
125                     if (opera[op-1] == '+' || opera[op-1] == '-' || opera[op-1] == '*' || opera[op-1] == '/' || opera[op-1] == ')' || opera[op-1] == '(')
126                     {
127                         switch (opera[op-1])
128                         {
129                         case '+':
130                             {
131                                 PushOperation(opera, ss, &op, &i);
132                                 break;
133                             }
134                         case '-':
135                             {
136                                 PushOperation(opera, ss, &op, &i);
137                                 break;
138                             }
139                         case '*':
140                             {
141                                 PushOperation(opera, ss, &op, &i);
142                                 break;
143                             }
144                         case '/':
145                             {
146                                 PushOperation(opera, ss, &op, &i);
147                                 break;
148                             }
149                         case '(':
150                             {
151                                 PushOperation(opera, ss, &op, &i);
152                                 break;
153                             }
154                         }
155                     }
156                     break;
157                 }
158             case '/':
159                 {
160                     if (op == 0)
161                     {
162                         PushOperation(opera, ss, &op, &i);
163                         break;
164                     }
165                     if (opera[op-1] == '+' || opera[op-1] == '-' || opera[op-1] == '*' || opera[op-1] == '/' || opera[op-1] == ')' || opera[op-1] == '(')
166                     {
167                         switch (opera[op-1])
168                         {
169                         case '+':
170                             {
171                                 PushOperation(opera, ss, &op, &i);
172                                 break;
173                             }
174                         case '-':
175                             {
176                                 PushOperation(opera, ss, &op, &i);
177                                 break;
178                             }
179                         case '*':
180                             {
181                                 PushOperation(opera, ss, &op, &i);
182                                 break;
183                             }
184                         case '/':
185                             {
186                                 PushOperation(opera, ss, &op, &i);
187                                 break;
188                             }
189                         case '(':
190                             {
191                                 PushOperation(opera, ss, &op, &i);
192                                 break;
193                             }
194                         }
195                     }
196                     break;
197                 }
198             case '(':
199                 {
200                     PushOperation(opera, ss, &op, &i);
201                     break;
202                 }
203             case ')':    /* 如果遇到右括號 */
204                 {
205                     while (opera[op-1] != '(')
206                     {
207                         num[j] = opera[op-1];    /* 將運算符棧中的元素依次入棧到后綴表達式棧中,直到遇到左括號為止 */
208                         j++;
209                         op--;
210                     }
211                     op--;
212                     i++;
213                     break;
214                 }
215             default:
216                 {
217                     printf("傳入表達式不符合要求\n");
218                     exit(0);
219                 }
220                     
221             }
222         }
223     }
224     while (op != 0)
225     {
226         num[j] = opera[op-1];    /* 將運算符棧中的元素依次入棧到后綴表達式棧中 */
227         j++;
228         op--;
229     }
230     num[j] = '\0';
231     i = 0;
232     while (num[i] != '\0')    /* 將后綴表達式存儲到傳入的形參ss中 */
233     {
234         ss[i] = num[i];
235         i++;
236     }
237     ss[i] = '\0';
238 }
239 
240 /* Function: 入運算符棧*/
241 void PushOperation(char *opera, char *ss, int *op, int *s)
242 {
243     opera[*op] = ss[*s];
244     (*op)++;
245     (*s)++;
246 }
View Code

 

后綴表達式的計算

完成了中綴表達式轉后綴表達式,接下來就是后綴表達式的計算了,后綴表達式的計算比中綴轉后綴要稍微簡單一點,只需要對我們轉換好的后綴表達式從左往右依次掃描,並依次入棧就行了,

意思是只需要用一個數組(double num[100])就OK了

需要考慮的情況如下

1、如果是數字,那么直接入棧到num中

2、如果是運算符,將棧頂的兩個數字出棧(因為我們考慮的運算符加、減、乘、除都是雙目運算符,只需要兩個操作數),出棧后對兩個數字進行相應的運算,並將運算結果入棧

3、直到遇到'\0'

下面用幾張圖,來直觀了解下這個過程,以上面轉換好的后綴表達式"123+*"為例(這里用ss來存儲后綴表達式,num來存儲計算結果,注意不要與上面圖中num搞混淆了)

 

 

(注意:這里將計算結果5入棧后,棧頂從之前的[3]變成[2])

到這里后綴表達式的計算就結束了,下面附上實現代碼

 

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 
  4 #define MAX 100
  5 
  6 void JudgeFopen_s(errno_t err);        /* 判斷文件打開是否成功 */
  7 void ReadFile(FILE *fp, char *ss);    /* 讀取文件內容 */
  8 double TransformCtoD(char ch);        /* 將char類型數組的每一個元素轉換為double */
  9 void CalculateAndPush(double *num, int *i, int *j, char mm);    /* 計算結果並入棧 */
 10 
 11 int main()
 12 {
 13     FILE *fp;
 14     errno_t err;
 15 
 16     char ss[MAX];    /* 存儲逆波蘭表達式 */
 17     int i = 0;
 18     int j = 0;
 19     double num[MAX];    /**/
 20     
 21     err = fopen_s(&fp, "E:\\ww.txt", "r");
 22 
 23     JudgeFopen_s(err);    /* 判斷文件打開是否成功 */
 24     ReadFile(fp, ss);    /* 讀取文件內容,存儲到ss中*/
 25 
 26     while (ss[i] != '\0')
 27     {
 28         if (ss[i] >= '0' && ss[i] <= '9')    /* 如果是數字 */
 29         {
 30             /* 因為num是char類型的,需要轉換為double類型方便計算 */
 31             num[j] = TransformCtoD(ss[i]);    /* 將數字存儲到棧中 */
 32             j++;
 33             i++;
 34         }
 35         else if (ss[i] == '+' || ss[i] == '-' || ss[i] == '*' || ss[i] == '/')
 36         {
 37             CalculateAndPush(num, &i, &j, ss[i]);    /* 計算結果並入棧 */
 38         }
 39         else if (ss[i] == '\n')    /* 如果是換行符,結束循環*/
 40         {
 41             break;
 42         }
 43     }
 44 
 45     printf("%lf", num[0]);
 46 
 47     return 0;
 48 }
 49 
 50 /* Function: 計算結果並入棧 */
 51 void CalculateAndPush(double *num, int *i, int *j, char mm)
 52 {
 53     switch (mm)
 54     {
 55     case '+':
 56         {
 57             num[(*j)-2] = num[(*j)-1] + num[(*j)-2];
 58             (*j)--;
 59             (*i)++;
 60             break;
 61         }
 62     case '-':
 63         {
 64             num[(*j)-2] = num[(*j)-1] - num[(*j)-2];
 65             (*j)--;
 66             (*i)++;
 67             break;
 68         }
 69     case '*':
 70         {
 71             num[(*j)-2] = num[(*j)-1] * num[(*j)-2];
 72             (*j)--;
 73             (*i)++;
 74             break;
 75         }
 76     case '/':
 77         {
 78             num[(*j)-2] = num[(*j)-1] / num[(*j)-2];
 79             (*j)--;
 80             (*i)++;
 81             break;
 82         }
 83     default:
 84         {
 85             exit(0);
 86         }
 87     }
 88 }
 89 /* Function: 判斷文件打開是否成功 */
 90 void JudgeFopen_s(errno_t err)
 91 {
 92     if (err != 0)
 93     {
 94         printf("文件打開失敗\n");
 95         system("pause");
 96         exit(0);
 97     }
 98 }
 99 
100 /* Function: 讀取文件內容*/
101 void ReadFile(FILE *fp, char *ss)
102 {
103     int i = 0;
104 
105     while (!feof(fp))
106     {
107         fscanf_s(fp, "%c", &ss[i]);
108         i++;
109     }
110     ss[i-1] = '\0';
111 }
112 
113 /* Function: 將char類型數組的每一個元素轉換為double */
114 double TransformCtoD(char ch)
115 {
116     return (double)(ch - '0');
117 }
View Code

 


免責聲明!

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



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