中綴表達式轉后綴表達式並計算——棧


發現以前給的鏈接搞錯了,尷尬

 


X = (56 - 20)*(4 - 3)/(4+2)   ;

那么計算機該怎么算呢?我們給出的方案是先轉化為中綴表達式(參考學過的離散),也就是X = 56#20#-4#3#-*4#2#+/  (用#表示一個數據的結束,便於記錄)

那接下來怎么辦呢?對於后綴表達式的處理我們可以利用棧來進行,把數據放入棧中,每當遇到一個運算符時,便出棧並處理一組數據,同時把這組數據的結果再次存入棧中,直到表達式處理結束,我么也就可以得到最后的結果。

// 我為什么要說也,我好像不記得了。。。。。。

那么問題來了,如何由中綴表達式轉換為后綴表達式?

先上代碼(PS:書上也有解法與本解法不同(本質一樣),可自行參考)

 1 template <class ElemType>
 2 void Trans(char * exp, int n, char * postexp) {    // 中綴轉后綴
 3     char e;
 4     SqStack <char> * Optr;            // 定義運算符棧指針 
 5     InitStack(Optr, n);        // 初始化運算符棧 
 6     int i = 0;  
 7     while (*exp != '\0') {
 8         switch (*exp) {
 9         case '(':Push(Optr, '(');        // 左括號進棧 
10             exp++;
11             break;
12         case ')':Pop(Optr, e);            // 右括號元素出棧
13             while (e != '(') {
14                 postexp[i++] = e;
15                 Pop(Optr, e);
16             }
17             exp++;
18             break;
19         case '+':
20         case '-':
21             while (StackEmpty(Optr)) {    // + || -棧不空循環 
22                 GetTop(Optr, e);        // 取棧頂元素 
23                 if (e != '(') {
24                     postexp[i++] = e;    // 將e存放到postexp中 
25                     Pop(Optr, e);
26                 }
27                 else
28                     break;                // 是 '(' 退出循環 
29             }
30             Push(Optr, *exp);            // + || -進棧 
31             exp++;
32             break;
33         case '*':
34         case '/':
35             while (StackEmpty(Optr)) {    // * || /棧不空循環 
36                 GetTop(Optr, e);
37                 if (e == '*' || e == '/') {
38                     postexp[i++] = e;
39                     Pop(Optr, e);
40                 }
41                 else
42                     break;
43             }
44             Push(Optr, *exp); 
45             exp++;
46             break;
47         default:            // 數字字符處理 
48             while (*exp >= '0' && *exp <= '9') {
49                 postexp[i++] = *exp;
50                 exp++;
51             }
52             postexp[i++] = '#';        // 標識一個數字串結束 
53         }
54     }
55     while (StackEmpty(Optr)) {        // exp掃描完畢
56         Pop(Optr, e);
57         postexp[i++] = e;
58     }
59     postexp[i] = '\0';        // 添加結束標識 
60     DestroyStack(Optr);        // 銷毀棧 
61 }

簡單來說,就是利用運算符的優先級來解決這些問題,對於中綴表達式轉化為后綴表達式,我們對運算符的處理是放入一個棧中,當 當前運算符優先級大於棧頂元素優先級時,進棧,反之,不斷退棧直到大於棧頂元素優先級為止;對於’(‘我們可以理解為進棧前優先級最高,進棧后優先級最低;

那么為什么要用模板寫呢?

接下來我們計算后綴表達式:

 1 template <class ElemType>
 2 double Compvalue(char *postexp, int n) {        // 后綴表達式計算
 3     double a, b, rsh, e;
 4     SqStack <double> * Opnd;        // 操作數棧 
 5     InitStack(Opnd, n);
 6     while (*postexp != '\0') {
 7         switch (*postexp) {
 8         case '+':Pop(Opnd, a);
 9             Pop(Opnd, b);        // + ->出棧兩個元素
10             Push(Opnd, a + b);
11             break;                // 元素進棧 
12         case '-':Pop(Opnd, a);
13             Pop(Opnd, b);
14             Push(Opnd, b - a);
15             break;
16         case '*':Pop(Opnd, a);
17             Pop(Opnd, b);
18             Push(Opnd, a*b);
19             break;
20         case '/':Pop(Opnd, a);
21             Pop(Opnd, b);
22             if (a != 0) {
23                 Push(Opnd, b / a);
24                 break;
25             }
26             else {
27                 cout << "除零錯誤!" << endl;
28                 exit(0);
29             }
30             break;
31         default:            // 數字字符處理
32             rsh = 0;
33             while (*postexp >= '0' && *postexp <= '9') {
34                 rsh = 10 * rsh + *postexp - '0';
35                 postexp++;
36             }
37             Push(Opnd, rsh);    // 進棧 
38             break;
39         }    
40         postexp++;    
41     }
42     GetTop(Opnd, e);
43     DestroyStack(Opnd);
44     return e;
45 }

需要把字符型數字轉化為int、double等類型,接下來,按照順序一個一個處理就可以了;(但是覺得還是有很多代碼類似,應該是可以把它合並簡化的)

好了,那為什么用模板我們也就知道了,因為我們用了兩個棧,一個是char棧,一個是double棧,如果定義兩個,那完全是重復了很多代碼,所以用模板會好一點,但是還有一個問題,在調用Trans函數和Compvalue函數時,如何實例化呢?顯然這也是一個問題。

函數實例化:https://blog.csdn.net/songchuwang1868/article/details/83024484 (無參函數的實例化)

 // 我也不太記得當初是怎么回事了,這個實例化好像也沒什么區別,當初是不太明白。

 // 記起來了,以前寫的是有參的實例化,直接帶入相應類型參數即可,所以無參查了一下,才明白是怎么回事。

加上一個比較詳細的實例化博客:CTHON

大家還可以考慮一下表達式的輸入問題;

差不多了,附上完整代碼

  1 #include<iostream>
  2 #include<cstdlib>
  3 #include<string>
  4 
  5 using namespace std;
  6 
  7 template <class ElemType>
  8 struct SqStack {        //
  9     ElemType *data;
 10     int top;            // 棧頂
 11 };
 12 
 13 template <class ElemType>
 14 void InitStack(SqStack <ElemType> *& s,int length) {    // 初始化
 15     s = (SqStack <ElemType> *)malloc(sizeof(SqStack <ElemType>));
 16     s->data = new ElemType[length];
 17     s->top = -1;
 18 }
 19 
 20 template <class ElemType>
 21 void DestroyStack(SqStack <ElemType> *& s) {        // 銷毀
 22     delete[] s->data;
 23     free(s);
 24 }
 25 
 26 template <class ElemType>
 27 bool StackEmpty(SqStack <ElemType> * s) {        // 空 = 0
 28     return (s->top != -1);            // 非空 = 1
 29 }
 30 
 31 template <class ElemType>
 32 void Push(SqStack <ElemType> *& s, ElemType e) {    // 進棧
 33     s->top++;
 34     s->data[s->top] = e;
 35 }
 36 
 37 template <class ElemType>
 38 bool Pop(SqStack <ElemType> *& s, ElemType & e) {     // 出棧
 39     if (s->top == -1)
 40         return false;
 41     e = s->data[s->top];
 42     s->top--;
 43     return true;
 44 }
 45 
 46 template <class ElemType>
 47 bool GetTop(SqStack <ElemType> *& s, ElemType & e) {    // 取棧頂元素
 48     if (s->top == -1)
 49         return false;
 50     e = s->data[s->top];
 51     return true;
 52 }
 53 
 54 template <class ElemType>
 55 void Trans(char * exp, int n, char * postexp) {    // 中綴轉后綴
 56     char e;
 57     SqStack <char> * Optr;            // 定義運算符棧指針 
 58     InitStack(Optr, n);        // 初始化運算符棧 
 59     int i = 0;  
 60     while (*exp != '\0') {
 61         switch (*exp) {
 62         case '(':Push(Optr, '(');        // 左括號進棧 
 63             exp++;
 64             break;
 65         case ')':Pop(Optr, e);            // 右括號元素出棧
 66             while (e != '(') {
 67                 postexp[i++] = e;
 68                 Pop(Optr, e);
 69             }
 70             exp++;
 71             break;
 72         case '+':
 73         case '-':
 74             while (StackEmpty(Optr)) {    // + || -棧不空循環 
 75                 GetTop(Optr, e);        // 取棧頂元素 
 76                 if (e != '(') {
 77                     postexp[i++] = e;    // 將e存放到postexp中 
 78                     Pop(Optr, e);
 79                 }
 80                 else
 81                     break;                // 是 '(' 退出循環 
 82             }
 83             Push(Optr, *exp);            // + || -進棧 
 84             exp++;
 85             break;
 86         case '*':
 87         case '/':
 88             while (StackEmpty(Optr)) {    // * || /棧不空循環 
 89                 GetTop(Optr, e);
 90                 if (e == '*' || e == '/') {
 91                     postexp[i++] = e;
 92                     Pop(Optr, e);
 93                 }
 94                 else
 95                     break;
 96             }
 97             Push(Optr, *exp); 
 98             exp++;
 99             break;
100         default:            // 數字字符處理 
101             while (*exp >= '0' && *exp <= '9') {
102                 postexp[i++] = *exp;
103                 exp++;
104             }
105             postexp[i++] = '#';        // 標識一個數字串結束 
106         }
107     }
108     while (StackEmpty(Optr)) {        // exp掃描完畢
109         Pop(Optr, e);
110         postexp[i++] = e;
111     }
112     postexp[i] = '\0';        // 添加結束標識 
113     DestroyStack(Optr);        // 銷毀棧 
114 }
115 
116 template <class ElemType>
117 double Compvalue(char *postexp, int n) {        // 后綴表達式計算
118     double a, b, rsh, e;
119     SqStack <double> * Opnd;        // 操作數棧 
120     InitStack(Opnd, n);
121     while (*postexp != '\0') {
122         switch (*postexp) {
123         case '+':Pop(Opnd, a);
124             Pop(Opnd, b);        // + ->出棧兩個元素
125             Push(Opnd, a + b);
126             break;                // 元素進棧 
127         case '-':Pop(Opnd, a);
128             Pop(Opnd, b);
129             Push(Opnd, b - a);
130             break;
131         case '*':Pop(Opnd, a);
132             Pop(Opnd, b);
133             Push(Opnd, a*b);
134             break;
135         case '/':Pop(Opnd, a);
136             Pop(Opnd, b);
137             if (a != 0) {
138                 Push(Opnd, b / a);
139                 break;
140             }
141             else {
142                 cout << "除零錯誤!" << endl;
143                 exit(0);
144             }
145             break;
146         default:            // 數字字符處理
147             rsh = 0;
148             while (*postexp >= '0' && *postexp <= '9') {
149                 rsh = 10 * rsh + *postexp - '0';
150                 postexp++;
151             }
152             Push(Opnd, rsh);    // 進棧 
153             break;
154         }    
155         postexp++;    
156     }
157     GetTop(Opnd, e);
158     DestroyStack(Opnd);
159     return e;
160 }
161 
162 int main()
163 {
164     double temp;
165     string str;
166     cin >> str;
167     char *exp = (char *)str.c_str();
168     char *postexp = new char [str.length()];
169     cout << "中綴表達式為:" << exp << endl;
170     Trans<char>(exp,str.length(),postexp);
171     cout << "轉換為后綴表達式為:" << postexp << endl;
172     temp = Compvalue<double>(postexp, str.length());
173     cout << "計算表達式的值為:" << temp << endl;
174     return 0;
175 }
View Code

 

2020-05-25


免責聲明!

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



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