1. 程式人生 > >棧的應用——表示式求值

棧的應用——表示式求值

  表示式求值是程式設計語言編譯中的一個基本問題,它的實現就是對“棧”的典型應用。本文針對表示式求值使用的是最簡單直觀的演算法“算符優先法”。

  本文給出兩種方式來實現表示式求值,方式一直接利用中綴表示式求值,需要用到兩個棧,運算元棧和操作符棧。首先置運算元棧為空棧, 操作符棧僅有“#”一個元素。依次讀入表示式中的每個字元,若是運算元則進運算元棧,若是操作符則和操作符棧的棧頂運算子比較優先權作相應操作,直至整個表示式求值完畢。方式二首先把中綴表示式轉換為字尾表示式並存儲起來,然後利用讀出的字尾表示式完成求值,其本質上是方式一的分解過程。

  表示式求值的程式碼如下:

#include <iostream>
#include 
"stack" #include "map" using namespace std; /* 只能求一位整數的加減乘除混合運算 */ map<char, pair<int, int>> priority; // 存放各個操作符的棧內棧外優先順序,first是棧內,second是棧外 char infix[50]; // 存放初始的中綴表示式 char postfix[50]; // 存放轉化的字尾表示式 int result; void MakePriority() //
構造運算子優先順序表 { priority.insert(make_pair('#', make_pair(0, 0))); // isp(#)=0, icp(#)=0 priority.insert(make_pair('\n', make_pair(0, 0))); // isp(\n)=0, icp(\n)=0 表示式結尾的'#'用'\n'代替,這樣可以省略表示式末尾的結束符'#' priority.insert(make_pair('(', make_pair(1, 6))); // isp(()=1, icp(()=6 priority.insert(make_pair('
*', make_pair(5, 4))); // isp(*)=5, icp(*)=4 priority.insert(make_pair('/', make_pair(5, 4))); // isp(/)=5, icp(/)=4 priority.insert(make_pair('%', make_pair(5, 4))); // isp(%)=5, icp(%)=4 priority.insert(make_pair('+', make_pair(3, 2))); // isp(+)=3, icp(+)=2 priority.insert(make_pair('-', make_pair(3, 2))); // isp(-)=3, icp(-)=2 priority.insert(make_pair(')', make_pair(6, 1))); // isp())=6, icp())=1 } void InfixToPostfix() // 把中綴表示式轉換為字尾表示式 { int i = 0; stack<char> optrStack; // 操作符棧 char optr; // optr為棧頂的操作符 optrStack.push('#'); while (!optrStack.empty()) { if (isdigit(infix[i])) // 是運算元則直接輸出(追加到postfix結尾) { postfix[strlen(postfix)] = infix[i]; postfix[strlen(postfix) + 1] = '\0'; i++; // 讀入中綴表示式的下一個字元 } else // 是操作符, 比較優先順序 { optr = optrStack.top(); // 取出棧頂操作符 if (priority[infix[i]].second > priority[optr].first) // icp(infix[i]) > isp(optr),infix[i]入棧 { optrStack.push(infix[i]); i++; } else if (priority[infix[i]].second < priority[optr].first)// icp(infix[i]) < isp(optr),optr退棧並輸出 { postfix[strlen(postfix)] = optr; postfix[strlen(postfix) + 1] = '\0'; optrStack.pop(); } else // icp(infix[i]) = isp(optr),退棧但不輸出,若退出的是'(',則繼續讀入下一個字元 { optrStack.pop(); if (optr == '(') i++; } } } } void CalculateByPostfix() // 通過後綴表示式求值 { int i = 0; stack<int> opndStack; // 運算元棧 int left, right; // 左右運算元 int value; // 中間結果 int newOpnd; while (postfix[i] != '#' && i < strlen(postfix)) { switch (postfix[i]) { case '+': right = opndStack.top(); // 從運算元棧中取出兩個運算元 opndStack.pop(); left = opndStack.top(); opndStack.pop(); value = left + right; opndStack.push(value); // 中間結果入棧 break; case '-': right = opndStack.top(); opndStack.pop(); left = opndStack.top(); opndStack.pop(); value = left - right; opndStack.push(value); break; case '*': right = opndStack.top(); opndStack.pop(); left = opndStack.top(); opndStack.pop(); value = left * right; opndStack.push(value); break; case '/': right = opndStack.top(); opndStack.pop(); left = opndStack.top(); opndStack.pop(); if (right == 0) { cerr << "Divide by 0!" << endl; } else { value = left / right; opndStack.push(value); } break; default: newOpnd = (int)(postfix[i] - 48); // 運算元直接入棧 opndStack.push(newOpnd); break; } i++; } result = opndStack.top(); } void CalculateByInfix() // 直接利用中綴表示式求值 { int i = 0; stack<char> optrStack; // 操作符棧 stack<int> opndStack; // 運算元棧 char optr; // optr為操作符棧頂的操作符 int left, right, value; // 左右運算元以及中間結果 optrStack.push('#'); optr = optrStack.top(); while (!optrStack.empty()) // 直到操作符棧為空 { if (isdigit(infix[i])) // 是運算元, 進運算元棧 { value = (int)(infix[i] - 48); opndStack.push(value); i++; } else // 是操作符, 比較優先順序 { optr = optrStack.top(); // 取出操作符棧頂的操作符 if (priority[infix[i]].second > priority[optr].first) // icp(infix[i]) > isp(optr),infix[i]入棧 { optrStack.push(infix[i]); i++; } else if (priority[infix[i]].second < priority[optr].first) // icp(infix[i]) < isp(optr),optr退棧並輸出 { optrStack.pop(); right = opndStack.top(); // 從運算元棧中取出兩個運算元 opndStack.pop(); left = opndStack.top(); opndStack.pop(); switch (optr) { case '+': value = left + right; opndStack.push(value); // 中間結果入棧 break; case '-': value = left - right; opndStack.push(value); // 中間結果入棧 break; case '*': value = left * right; opndStack.push(value); // 中間結果入棧 break; case '/': if (right == 0) { cerr << "Divide by 0!" << endl; } else { value = left / right; opndStack.push(value); } break; default: break; } } else { optrStack.pop(); if (optr == '(') i++; } } } result = opndStack.top(); } int main() { MakePriority(); // 構造運算子優先順序表 cout << "請輸入中綴表示式:"; cin >> infix; cout << "直接利用中綴表示式求值為:"; CalculateByInfix(); cout << result << endl; cout << "轉化為字尾表示式:"; InfixToPostfix(); for (int i = 0;i < strlen(postfix);i++) { cout << postfix[i]; } cout << endl; cout << "利用字尾表示式求值為:"; CalculateByPostfix(); cout << result << endl; return 0; }

  為了方便起見,本文只是簡單的設計了一個針對一位整數的四則運算進行求值的演算法,對於處理多位整數的四則運算,需要對本文接受輸入的資料型別進行“升階”,把字元陣列換成字串陣列,將一個整數的多位數字存入一個字串進行處理。