C++:后綴表達式


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM