發現以前給的鏈接搞錯了,尷尬
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 }
2020-05-25