分析:
中綴表達式的操作符以中綴的形式處於操作數的中間。
若創建一個數字棧,一個運算符棧,並將一個中綴表達式從左至右壓入棧這兩個棧中。先向數字棧壓入一個數字,再向運算符棧壓入一個運算符,接著向數字棧壓入數字。此時數字棧中有兩個元素,字符棧中有一個元素。
當開始讀到第二個運算符時就判斷當前准備壓入運算符與之前已在棧中運算符的優先級順序,若棧頂的運算符優先順序大於或等於當前即將壓入的運算符,則彈出兩個數字棧中的元素和一個運算符棧中的元素進行運算,將結果重新壓回數字棧中,然後將當前的讀到的運算符壓入數字棧中。(例如:數字棧中含有4(棧頂)3,運算符棧中含有+(棧頂),讀到*時,則先彈出4,3,和+,4+3進行計算得到7,並將7壓入數字棧,然後將*壓入棧中,完成後數字棧中含有7(棧頂),運算符棧中含有*(棧頂)
若優先級小於當前運算符,則直接將當前運算符壓入棧中。(例如:運算符中存在+,當讀到*時,直接壓入棧中,不進行運算。)
因此數字棧中的元素至多有3個,操作符棧中的元素至多2個,且每次操作完成後,數字棧中的元素一定比操作符棧的元素多一個。
當對表達式讀取完成後,對棧進行運算(數字棧彈出兩個數字,操作符棧彈出一個操作符,並將運算結果壓回數字棧中),直至操作符棧位空結束,數字棧中剩余的元素即為該中綴表達式的運算結果。
對於(),可以將其之間的內容視作一個獨立式,獨立於它前後的運算符。當讀到(時,將其直接壓入棧;讀到)時,將()之間的表達式進行計算,得到一個數字,最終()之間的內容就等價於一個數字。
代碼:
1 #include "stdafx.h" 2 #include <stack> 3 #include <string> 4 #include <iostream> 5 #include <stdio.h>//用於double與string的轉換 6 using namespace std; 7 double calExp(string); 8 void calStack(stack<double>&, stack<char>&); 9 int _tmain(int argc, _TCHAR* argv[]) 10 { 11 string infixExp;// 中綴表達式 12 for (;;){ 13 cout << "輸入一個合法的表達式,無輸入則退出" << endl; 14 getline(cin, infixExp); 15 if (infixExp == "")break; 16 cout << "計算結果為:" << calExp(infixExp) << endl; 17 } 18 } 19 void calStack(stack<double>& numStack, stack<char>& opStack){//彈出兩個數字和一個符號進行一次運算,並將得到結果壓入數字棧中. 20 double num2 = numStack.top(); 21 numStack.pop(); 22 double num1 = numStack.top(); 23 numStack.pop(); 24 double num = 0;//運算結果 25 switch (opStack.top()) 26 { 27 case'+': 28 num = num1 + num2; 29 break; 30 case'-': 31 num = num1 - num2; 32 break; 33 case'*': 34 num = num1*num2; 35 break; 36 case'/': 37 num = num1 / num2; 38 break; 39 } 40 numStack.push(num); 41 opStack.pop(); 42 } 43 double calExp(string exp){ 44 char token;//exp中讀取的位置 45 stack<double>numStack;//數字棧 46 stack <char> opStack;//運算符棧 47 double number1 = 0, number2 = 0;//數字棧彈出的進行兩個運算的數字 48 for (int i = 0; i < exp.length(); i++){//按順序掃描exp中所有的元素 49 token = exp[i]; 50 switch (token) 51 { 52 case ' ': break; 53 case '+':case'-': 54 if (numStack.size() < 2 || opStack.size()<1 ||opStack.top()=='('){ 55 opStack.push(token); 56 } 57 else 58 { 59 calStack(numStack, opStack); 60 opStack.push(token); 61 } 62 break; 63 case'*':case'/'://若遇到*/,優先級最高 直接壓入棧中 64 if (numStack.size() < 2 || opStack.size()<1 || opStack.top() == '+' || opStack.top() == '-'||opStack.top() == '('){ 65 opStack.push(token); 66 } 67 else 68 { 69 calStack(numStack, opStack); 70 opStack.push(token); 71 } 72 break; 73 case'(': 74 opStack.push(token); 75 break; 76 case')': 77 for (;;){//將()中的元素進行運算 78 if (opStack.top() == '('){ 79 opStack.pop(); 80 break; 81 } 82 calStack(numStack, opStack); 83 } 84 break; 85 default: 86 string inNum;//壓入棧中的數字 87 inNum.append(1,token);//先將第一個數字存入inNum 88 for (;;){//讀取多位的數字 89 if (!isalnum(exp[i + 1]) && (exp[i + 1])!='.')break;//非數字時停止(不包括小數點) 90 i++; 91 token = exp[i]; 92 inNum.append(1,token);// 93 } 94 double number=atof(inNum.c_str());//將字符串轉換為數字壓入棧中 95 numStack.push(number); 96 break; 97 } 98 } 99 for (;;){// 100 if (opStack.empty())break; 101 calStack(numStack, opStack); 102 } 103 return numStack.top(); 104 }
運行結果:
存在的問題:
本方法未考慮未知數(字母,如x,y),輸入未知數時運算將出現錯誤。
未進行錯誤檢測,當輸入的中綴表達式不規范時,將會報錯。