(棧)C++中綴表示式轉字尾表示式(可處理多位數字)
阿新 • • 發佈:2018-12-31
題目描述:輸入合法的算術表示式(中綴表示式),輸出原始字串,轉換後的字尾表示式,以及計算結果。
題目考察點:棧的應用,掌握棧先入後出的特點。
演算法思路:中綴表示式轉字尾的演算法採用排程場演算法。當讀入一個數字,就將數字輸出;當讀入一個運算子時,如果此時運算子棧為空就將運算子壓棧,如果運算子棧不為空,就比較當前運算子和棧頂運算子的優先順序,如果當前運算子優先順序大於棧頂運算子,則將當前運算子壓棧,如果優先順序小於等於當前運算子,則將棧頂運算子彈出放至輸出佇列後,繼續比較當前運算子與棧頂運算子優先順序,重複上述過程,直到當前運算子被壓棧。(事實上,這隻針對左結合性的運算子,而加減乘除都是左結合性)。如果有括號,讀到左括號就壓棧,當讀到右括號就將在左括號之後壓棧的所有運算子依次彈出,當然也將左括號彈出。當讀取結束後,棧中還有運算子就將剩餘的運算子依次彈出。此時得到的即為輸出佇列。
在這裡放上一個維基百科的例子。
輸入 | 動作 | 輸出 (逆波蘭表示法) | 運算子棧 | 提示 |
---|---|---|---|---|
3 | 將符號加入輸出佇列 | 3 | ||
+ | 將符號壓入操作符堆疊 | 3 | + | |
4 | 將符號加入輸出佇列 | 3 4 | + | |
* | 將符號壓入操作符堆疊 | 3 4 | * + | *號的優先順序高於+號 |
2 | 將符號加入輸出佇列 | 3 4 2 | * + | |
/ | 將堆疊中元素彈出,加入輸出佇列 | 3 4 2 * | + | /號和*號優先順序相同 |
將符號壓入操作符堆疊 | 3 4 2 * | / + | /號的優先順序高於+號 | |
( | 將符號壓入操作符堆疊 | 3 4 2 * | ( / + | |
1 | 將符號加入輸出佇列 | 3 4 2 * 1 | ( / + | |
− | 將符號壓入操作符堆疊 | 3 4 2 * 1 | − ( / + | |
5 | 將符號加入輸出佇列 | 3 4 2 * 1 5 | − ( / + | |
) | 將堆疊中元素彈出,加入輸出佇列 | 3 4 2 * 1 5 − | ( / + | 迴圈直到找到(號 |
將堆疊元素彈出 | 3 4 2 * 1 5 − | / + | 括號匹配結束 | |
^ | 將符號壓入操作符堆疊 | 3 4 2 * 1 5 − | ^ / + | ^號的優先順序高於/號 |
2 | 將符號加入輸出佇列 | 3 4 2 * 1 5 − 2 | ^ / + | |
^ | 將符號壓入操作符堆疊 | 3 4 2 * 1 5 − 2 | ^ ^ / + | ^號為從右至左求值 |
3 | 將符號加入輸出佇列 | 3 4 2 * 1 5 − 2 3 | ^ ^ / + | |
END | 將棧中所有資料加入輸出佇列 | 3 4 2 * 1 5 − 2 3 ^ ^ / + |
至於計算就比較簡單,只需要對字尾表示式進行計算即可。將字尾表示式依次壓棧,讀到數字就壓棧,讀到運算子就從棧中彈出兩個元素做運算,再把結果彈入棧。這裡需要注意的一個問題是,運算時需要用第二個彈出的元素對第一個彈出的元素做運算,比如字尾表示式為21-,此時2壓棧,1壓棧,讀到-號時,先彈出1,再彈出2,則運算2-1.(即次棧頂元素op棧頂元素)
程式碼如下:
#include<iostream>
#include<stack>
#include<string>
#include<cctype>
using namespace std;
bool isNumber(char s)//用於判定是否是數字
{
if(isdigit(s))
{
return true;
}
return false;
}
//用數字表示優先順序,把‘+’和‘-’定義為1,‘*’和‘/’定義為2,數字大代表優先順序大
int priorOfOperator(char operator_s)
{
int temp = 0;
if(operator_s == '+'||operator_s == '-')
{
temp = 1;
}
else if(operator_s == '*' || operator_s == '/')
{
temp = 2;
}
return temp;
}
/*處理運算子,遇到運算子比棧頂優先順序高的,則壓棧
否則替代棧頂的運算子,將棧頂運算子加入輸出佇列*/
void handleStackOperator(string& result, char currOper, stack<char>& operators)
{
if(operators.size() == 0)
{
operators.push(currOper);
return;
}
if(priorOfOperator(currOper) > priorOfOperator(operators.top()))
{
operators.push(currOper);
}
else
{
cout<<operators.top();
result += operators.top();
operators.pop();
return handleStackOperator(result, currOper, operators);
}
}
//有左括號時直接入棧,然後正常操作,遇到右括號時,將左右括號之間所有運算子出棧
void handleOperator(string& result, char currOper, stack<char>& operators)
{
if(operators.size() == 0)
{
operators.push(currOper);
return;
}
if(currOper == '+' || currOper == '-' ||
currOper == '*' || currOper == '/')
{
handleStackOperator(result, currOper, operators);
}
else if(currOper == '(')
{
operators.push(currOper);
}
else if(currOper == ')')
{
while(operators.top()!='(')
{
cout<<operators.top();
result += operators.top();
operators.pop();
}
operators.pop();
return;
}
}
//計算結果
float caclResult(string& s)
{
stack<int> result;
for(int i = 0; i < (int)s.length(); i++)
{
if(isNumber(s[i]))
{
result.push(s[i] - '0');
}
else
{
int temp2 = result.top();
result.pop();
int temp1 = result.top();
result.pop();
if(s[i] == '+')
{
result.push(temp1+temp2);
}
else if(s[i] == '-')
{
result.push(temp1-temp2);
}
else if(s[i] == '*')
{
result.push(temp1*temp2);
}
else if(s[i] == '/')
{
result.push(temp1/temp2);
}
}
}
return result.top();
}
int main()
{
string test = "";
string result = "";//用來存字尾表示式,便於最後做計算
cin>>test;//讀入合法的算術表示式
cout<<test<<endl;;
stack<char> test_stack;
for(int i = 0; i<(int)test.length();i++)
{
if(isNumber(test[i]))
{
cout<<test[i];
result += test[i];
}
else
{
handleOperator(result, test[i],test_stack);
}
}
while(test_stack.size() != 0)//運算子棧不為空則將剩下的全部彈出
{
cout<<test_stack.top();
result += test_stack.top();
test_stack.pop();
}
cout<<endl;
cout<<caclResult(result)<<endl;//計算結果
return 0;
}