棧實現表示式求值(C++)
阿新 • • 發佈:2019-02-03
為了實現用棧計算算數表示式的值,需設定兩個工作棧:用於儲存運算子的棧opter,以及用於儲存運算元及中間結果的棧opval。
演算法基本思想如下:
(1)首先將運算元棧opval設為空棧,而將'#'作為運算子棧opter的棧底元素,這樣的目的是判斷表示式是否求值完畢。
(2)依次讀入表示式的每個字元,表示式須以'#'結尾,若是運算元則入棧opval,若是運算子,則將此運算子c與opter的棧頂元素top比較優先順序後執行相應的操作,(具體操作如下:(i)若top的優先順序小於c,即top<c,則將c直接入棧opter,並讀入下一字元賦值給c;(ii)若top的優先順序等於c,即top=c,則彈出opter的棧頂元素,並讀入下一字元賦值給c,這一步目的是進行括號操作;(iii)若top優先順序高於c,即top>c,則表明可以計算,此時彈出opval的棧頂兩個元素,並且彈出opter棧頂的的運算子,計算後將結果放入佔opval中。)直至opter的棧頂元素和當前讀入的字元均為'#',此時求值結束。
算符間的優先關係如下表所示:
表中需要注意的是θ1為opter的棧頂元素,θ2位從表示式中讀取的操作符,此優先順序表可以用二維陣列實現,具體見程式碼(表來源:嚴蔚敏《資料結構》)。
具體程式碼如下:
[cpp] view plain copy print?- #include<iostream> //輸入的表示式要以'#'結尾,如‘5+6*3/(3-1)#’
- #include<cstring>
- #include<cstdio>
- #include<cctype>
- #include<stack>
- usingnamespace std;
- stack<char
- stack<double> opval; //運算元棧
- int getIndex(char theta) //獲取theta所對應的索引
- {
- int index = 0;
- switch (theta)
- {
- case'+':
- index = 0;
- break;
- case'-':
- index = 1;
- break;
- case'*':
- index = 2;
- break;
- case'/':
- index = 3;
- break;
- case'(':
- index = 4;
- break;
- case')':
- index = 5;
- break;
- case'#':
- index = 6;
- default:break;
- }
- return index;
- }
- char getPriority(char theta1, char theta2) //獲取theta1與theta2之間的優先順序
- {
- constchar priority[][7] = //算符間的優先順序關係
- {
- { '>','>','<','<','<','>','>' },
- { '>','>','<','<','<','>','>' },
- { '>','>','>','>','<','>','>' },
- { '>','>','>','>','<','>','>' },
- { '<','<','<','<','<','=','0' },
- { '>','>','>','>','0','>','>' },
- { '<','<','<','<','<','0','=' },
- };
- int index1 = getIndex(theta1);
- int index2 = getIndex(theta2);
- return priority[index1][index2];
- }
- double calculate(double b, char theta, double a) //計算b theta a
- {
- switch (theta)
- {
- case'+':
- return b + a;
- case'-':
- return b - a;
- case'*':
- return b * a;
- case'/':
- return b / a;
- default:
- break;
- }
- }
- double getAnswer() //表示式求值
- {
- opter.push('#'); //首先將'#'入棧opter
- int counter = 0; //新增變數counter表示有多少個數字相繼入棧,實現多位數的四則運算
- char c = getchar();
- while (c != '#' || opter.top() != '#') //終止條件
- {
- if (isdigit(c)) //如果c在'0'~'9'之間
- {
- if (counter == 1) //counter==1表示上一字元也是數字,所以要合併,比如12*12,要算12,而不是單獨的1和2
- {
- double t = opval.top();
- opval.pop();
- opval.push(t * 10 + (c - '0'));
- counter = 1;
- }
- else
- {
- opval.push(c - '0'); //將c對應的數值入棧opval
- counter++;
- }
- c = getchar();
- }
- else
- {
- counter = 0; //counter置零
- switch (getPriority(opter.top(), c)) //獲取運算子棧opter棧頂元素與c之間的優先順序,用'>','<','='表示
- {
- case'<': //<則將c入棧opter
- opter.push(c);
- c = getchar();
- break;
- case'=': //=將opter棧頂元素彈出,用於括號的處理
- opter.pop();
- c = getchar();
- break;
- case'>': //>則計算
- char theta = opter.top();
- opter.pop();
- double a = opval.top();
- opval.pop();
- double b = opval.top();
- opval.pop();
- opval.push(calculate(b, theta, a));
- }
- }
- }
- return opval.top(); //返回opval棧頂元素的值
- }
- int main()
- {
- //freopen("test.txt", "r", stdin);
- int t; // 需要計算的表示式的個數
- cin >> t;
- getchar();
- while (t--)
- {
- while (!opter.empty())opter.pop();
- while (!opval.empty())opval.pop();
- double ans = getAnswer();
- cout << ans << endl<< endl;
- getchar();
- }
- return 0;
- }
#include<iostream> //輸入的表示式要以'#'結尾,如‘5+6*3/(3-1)#’
#include<cstring>
#include<cstdio>
#include<cctype>
#include<stack>
using namespace std;
stack<char> opter; //運算子棧
stack<double> opval; //運算元棧
int getIndex(char theta) //獲取theta所對應的索引
{
int index = 0;
switch (theta)
{
case '+':
index = 0;
break;
case '-':
index = 1;
break;
case '*':
index = 2;
break;
case '/':
index = 3;
break;
case '(':
index = 4;
break;
case ')':
index = 5;
break;
case '#':
index = 6;
default:break;
}
return index;
}
char getPriority(char theta1, char theta2) //獲取theta1與theta2之間的優先順序
{
const char priority[][7] = //算符間的優先順序關係
{
{ '>','>','<','<','<','>','>' },
{ '>','>','<','<','<','>','>' },
{ '>','>','>','>','<','>','>' },
{ '>','>','>','>','<','>','>' },
{ '<','<','<','<','<','=','0' },
{ '>','>','>','>','0','>','>' },
{ '<','<','<','<','<','0','=' },
};
int index1 = getIndex(theta1);
int index2 = getIndex(theta2);
return priority[index1][index2];
}
double calculate(double b, char theta, double a) //計算b theta a
{
switch (theta)
{
case '+':
return b + a;
case '-':
return b - a;
case '*':
return b * a;
case '/':
return b / a;
default:
break;
}
}
double getAnswer() //表示式求值
{
opter.push('#'); //首先將'#'入棧opter
int counter = 0; //新增變數counter表示有多少個數字相繼入棧,實現多位數的四則運算
char c = getchar();
while (c != '#' || opter.top() != '#') //終止條件
{
if (isdigit(c)) //如果c在'0'~'9'之間
{
if (counter == 1) //counter==1表示上一字元也是數字,所以要合併,比如12*12,要算12,而不是單獨的1和2
{
double t = opval.top();
opval.pop();
opval.push(t * 10 + (c - '0'));
counter = 1;
}
else
{
opval.push(c - '0'); //將c對應的數值入棧opval
counter++;
}
c = getchar();
}
else
{
counter = 0; //counter置零
switch (getPriority(opter.top(), c)) //獲取運算子棧opter棧頂元素與c之間的優先順序,用'>','<','='表示
{
case '<': //<則將c入棧opter
opter.push(c);
c = getchar();
break;
case '=': //=將opter棧頂元素彈出,用於括號的處理
opter.pop();
c = getchar();
break;
case '>': //>則計算
char theta = opter.top();
opter.pop();
double a = opval.top();
opval.pop();
double b = opval.top();
opval.pop();
opval.push(calculate(b, theta, a));
}
}
}
return opval.top(); //返回opval棧頂元素的值
}
int main()
{
//freopen("test.txt", "r", stdin);
int t; // 需要計算的表示式的個數
cin >> t;
getchar();
while (t--)
{
while (!opter.empty())opter.pop();
while (!opval.empty())opval.pop();
double ans = getAnswer();
cout << ans << endl<< endl;
getchar();
}
return 0;
}
結果: