1.基本概念
后綴表示法也叫逆波蘭表示法(前綴就是波蘭表示法),由於所有的操作符都在操作數的后面,所以被稱為后綴表示法。
中綴表示法的操作符在操作數之間,也是最符合人的邏輯。前綴表示法的操作符在操作數之前,它和后綴表示法一樣,都是為了方便計算機計算,因為在后綴或前綴中沒有括號,也不存在優先級處理的問題,直接利用棧進行計算。
示例:
中綴:5+(1+2)*4-3
后綴:512+4*+3-
2.中綴表示轉后綴表示
中綴轉后綴可以從左向右掃描表達式,然后按照規則進行處理, 對於中綴表達式a+(b+c)*d-e的轉換步驟:
(1). 首先初始化兩個棧:輸出棧rpn_和操作符棧rpn_stack
(2). 從左至右掃描表達式,遇到操作數則直接壓入輸出棧,在遇到a時,由於是操作數,將"a"壓入rpn_
(3). 繼續掃描,遇到操作符時,如果該操作符優先級高於rpn_stack棧頂的操作符,則直接壓入rpn_stack,如果同級或低於棧頂操作符,則將棧中操作符依次彈出(同時壓入輸出棧)直到遇到比當前操作符優先級低的(或者遇到了"("),然后壓入操作符。(注意,對於操作符"(",只有")"才能將其彈出,其他情況不彈出"(")。現在我們掃描到了"+",由於當前的操作符棧空,直接壓入。
(4). 然后讀取到"(",由於它的優先級是最高的,只要遇到就直接壓入棧。
(5). 然后讀取到操作數"b",壓入輸出棧 rpn_。
(6). 繼續讀取到 "+" ,當前操作符棧的棧頂是"(",因為只有")"才能將其彈出,所以"+"入棧。
(7). 讀取的"c"壓入輸出棧。
(8). 讀取到了")",此時開始將操作符棧的操作符依次彈出(同時壓入輸出棧),直到遇到第一個"(",將"("彈出。("("和")"都不能進入輸出棧)
(9). 然后讀取到" * ",當前操作符棧的棧頂是"+",優先級低於" * ",所以直接壓入棧。
(10). 讀取的"d"壓入輸出棧
(11). 讀取到"-",當前棧頂是" * ",比"-"的優先級高,所以" * "彈出(同時壓入輸出棧,下同),然后棧頂"+"的優先級和"-"相同,也要彈出。此時操作符棧空,"-"壓入
(12). 讀取到了"e",壓入輸出棧,此時表達式讀取完畢,將操作符棧依次彈出並壓入輸出棧,完成了轉換,輸出為
abc+d*+e-。
以下是將中綴表達式轉化為后綴表達式的代碼:
// 比較操作符A和操作符B的優先級
bool opAisBiggerThanOpB(string opA, string opB)
{
if (opA == "*" || opA == "/" && opB != "*" && opB != "/" && opB!= "(")
return true;
else
return false;
}
// 中綴表達式轉后綴表達式
bool parseFormula(string formula)
{
vector<string> rpn_; // 總輸出
vector<string> rpn_stack; // 符號堆棧
string sign_; // 臨時保存操作數
for (int i = 0; i < formula.size(); ++i)
{
if (formula[i] != '+'&&formula[i] != '-'&&formula[i] != '*'&&formula[i] != '/' && formula[i] != '(' &&formula[i] != ')') // 如果是操作數的話就保存起來等待輸出
{
sign_ += formula[i];
}
else
{
string t_formula;
t_formula += formula[i];
// 操作數輸出
if (!sign_.empty())
{
rpn_.push_back(sign_);
sign_.clear(); // 清空,保存下一個操作數
}
//操作符入棧
if (t_formula == ")")
{
while (rpn_stack[rpn_stack.size() - 1] != "(")
{
if (rpn_stack.empty())
return false;
rpn_.push_back(rpn_stack[rpn_stack.size() - 1]);
rpn_stack.pop_back();
}
rpn_stack.pop_back();
}
else if (rpn_stack.empty())
rpn_stack.push_back(t_formula);
else if (t_formula == "(" || rpn_stack[rpn_stack.size() - 1] == "(")
rpn_stack.push_back(t_formula);
else if (opAisBiggerThanOpB(t_formula, rpn_stack[rpn_stack.size() - 1]))
rpn_stack.push_back(t_formula);
else
{
while (!opAisBiggerThanOpB(t_formula, rpn_stack[rpn_stack.size() - 1]) && rpn_stack[rpn_stack.size() - 1]!="(")
{
rpn_.push_back(rpn_stack[rpn_stack.size() - 1]);
rpn_stack.pop_back();
if (rpn_stack.empty())
break;
}
rpn_stack.push_back(t_formula);
}
} // end else
} // end for
// 處理最后的還留在暫存區的操作數和操作符
if (!sign_.empty())
rpn_.push_back(sign_);
if(!rpn_stack.empty())
{
for(int i = rpn_stack.size()-1;i>=0;--i)
rpn_.push_back(rpn_stack[i]);
}
// 輸出測試
string rpn;
for (int i = 0; i < rpn_.size(); ++i)
{
rpn += rpn_[i];
}
cout << rpn << endl;
return true;
}
例如:parseFormula("5+((1+2)*4)-3");
輸出為:512+4*+3-
3.后綴表達式的計算
對於后綴表達式:5 1 2 + 4 * + 3 -:
(1). 首先建立一個棧 res 用來保存中間值,從左到右讀取后綴表達式,遇到操作數直接入棧,遇到操作符則將棧頂的兩個操作數彈出,完成計算后將計算結果壓入棧。
(2). 首先讀取了 5、1、2,將它們依次入棧,當前的棧:
res:
棧底5 1 2棧頂
(3). 然后讀取到操作符"+",彈出2,然后彈出1,將
1+2的運算結果3壓入棧:
res:
棧底5 3棧頂
(4). 然后讀取到的操作數"4"入棧,接着讀取到" * ",如同上面,將4彈出,將3彈出,計算
3*4然后將12壓入棧。
(5). 后面的操作和前面一樣。
(6). 結果:14
