在程序設計中,可能碰到需要對字符串數學表達式求值的問題,常用的方法是解析表達式,生成二叉樹,然後進行計算。編譯器就是使用這種方法來解析程序中的表達式的。這種方法實現起來有點難度,需要考慮運算符的優先級,括號的配對,堆棧的使用等等。我們正常情況下看到的數學表達式如果用二叉樹遍歷的話,恰好是中序遍歷,故叫做中序表達式。除此之外,還有前序表達式,後序表達式。如:a+b+c(中序),++abc(前序),ab+c+(後序),如果表達式含有×,/,()等就更復雜了。
後綴表達式也稱逆波蘭表達式 因其使表達式求值變得輕鬆,所以被普遍使用。
逆波蘭式:
在通常的表達式中,二元運算符總是置於與之相關的兩個運算對象之間(如:1+1),所以這種表示法也稱爲中綴表示。波蘭邏輯學家J.Lukasiewicz於1929年提出了另一種表示表達式的方法,稱爲逆波蘭記法,在逆波蘭記法中,所有操作符置於操作數的後面,因此也被稱爲後綴表示法。示例如下:
中綴表示 |
逆波蘭式 |
a+b |
a,b,+ |
a+(b-c) |
a,b,c,-,+ |
a+(b-c)*d |
a,b,c,-,d,*,+ |
a+d*(b-c) |
a,d,b,c,-,*,+ |
a=1+3 |
a=1,3 + |
逆波蘭表達式是一種十分有用的表達式,它將複雜表達式轉換爲可以依靠簡單的操作得到計算結果的表達式。它的優勢在於只用兩種簡單操作,入棧和出棧就可以搞定任何普通表達式的運算。
中綴表達式轉換爲逆波蘭式:
將一個普通的中序表達式轉換爲逆波蘭表達式的一般算法是:
1、首先構造一個運算符棧,此運算符在棧內遵循越往棧頂優先級越高的原則。
2、讀入一箇中綴表達式,爲了方便起見,可在其最右端追加一個最低優先級運算符(如:#號)。(這樣做的目的是,最後讀入#號運算符時將運算符棧中所有運算符都輸出)。
3、從左至右掃描該中綴表達式,如果當前字符是數字,則分析到該數字串的結束,並將該數字串直接輸出。
4、如果不是數字,該字符則是運算符,此時需比較該運算符與運算符棧頂運算符的優先關係:
(1)、若該運算符優先級高於棧頂運算符優先級別(或棧爲空),則直接將該運算符壓入運算符棧中;
(2)、若該運算符優先級小於或等於此運算符棧頂的運算符,則彈出棧頂運算符並輸出,重複比較、輸出,直到棧爲空或該運算符優先級高於棧頂運算符,然後將該運算符入棧。
5、重複上述操作(3)-(4)直至掃描完整個簡單算術表達式,確定所有字符都得到正確處理,輸出結果便是中綴表達式轉化爲逆波蘭表示的簡單算術表達式。
運算符優先級參考:
優先級分爲棧內優先級isp(Instack priority)和棧外優先級icp(In coming priority)。除了括號以外,其他運算符進棧後優先級都升1,這樣可以體現在中綴表達式中相同優先級的操作符自左向右計算的要求,讓位於棧頂的操作符先退棧並輸出。各運算符及符號優先級:
操作符 |
# |
^ |
*,/,% |
+,- |
( |
) |
isp |
0 |
7 |
5 |
3 |
1 |
8 |
icp |
0 |
6 |
4 |
2 |
8 |
1 |
後綴表達式建立二叉樹:
//後綴表達式建樹 樣例:1 2 3 * + 4 -
void ExpTree::PostOrderCreate(string str)
{
Stack<TNode*> nodeStack;
for (int i = 0; i < str.length(); i++)
{
if (str[i] == ' ') // 分隔符
continue;
switch (str[i])
{
case '+': case '-': case '*': case '/':
nodeStack.push(new TNode(str[i], nodeStack.pop(), nodeStack.pop()));
break;
default:
nodeStack.push(new TNode(str[i] - '0'));
break;
}
}
m_pRoot = nodeStack.pop();
}
計算二叉樹表達式值:
//計算
int ExpTree::Cacul(int a, char op, int b)
{
switch (op)
{
case '+': return a + b;
case '-': return a - b;
case '*': return a * b;
case '/': return a / b;
}
}
//求值函數
int ExpTree::Caculate(TNode* cur)
{
if (cur->left == NULL && cur->right == NULL)
return cur->opnd;
else
return Cacul(val(cur->left), cur->optr, val(cur->right));
}
源代碼下載:http://download.csdn.net/source/3219514
轉自原文:http://blog.csdn.net/simplebelief/article/details/6347149