波蘭表示法, 也叫前綴表示法。
運算波蘭表達式時,無需記住運算的層次,只需要直接尋找第一個運算的操作符。以二元運算為例,從左至右讀入表達式,遇到一個操作符后跟隨兩個操作數時,則計算之,然后將結果作為操作數替換這個操作符和兩個操作數;重復此步驟,直至所有操作符處理完畢。因為在正確的前綴表達式中,操作數必然比操作符多一個,所以必然能找到一個操作符符合運算條件;而替換時,兩個操作數和一個操作符替換為一個操作數,所以減少了各一個操作符和操作數,仍然可以迭代運算直至計算整個式子。多元運算也類似,遇到足夠的操作數即產生運算,迭代直至完成。迭代結束的條件由表達式的正確性來保證。下面是一個例子,演示了每一步的運算順序:
其特點是操作符置於操作數的前面,因此也稱做前綴表示法。如果操作符的元數(arity)是固定的,則語法上不需要括號仍然能被無歧義地解析
計算方法:
運算波蘭表達式時,無需記住運算的層次,只需要直接尋找第一個運算的操作符。以二元運算為例,從左至右讀入表達式,遇到一個操作符后跟隨兩個操作數時,則計算之,然后將結果作為操作數替換這個操作符和兩個操作數;重復此步驟,直至所有操作符處理完畢。因為在正確的前綴表達式中,操作數必然比操作符多一個,所以必然能找到一個操作符符合運算條件;而替換時,兩個操作數和一個操作符替換為一個操作數,所以減少了各一個操作符和操作數,仍然可以迭代運算直至計算整個式子。多元運算也類似,遇到足夠的操作數即產生運算,迭代直至完成。迭代結束的條件由表達式的正確性來保證。下面是一個例子,演示了每一步的運算順序:
− × ÷ 15 − 7 + 1 1 3 + 2 + 1 1 =
− × ÷ 15 − 7 2 3 + 2 + 1 1 =
− × ÷ 15 5 3 + 2 + 1 1 =
− × 3 3 + 2 + 1 1 =
− 9 + 2 + 1 1 =
− 9 + 2 2 =
− 9 4 =
5
等價的中綴表達式: ((15 ÷ (7 − (1 + 1))) × 3) − (2 + (1 + 1)) = 5
下面的偽代碼用一個stack求prefix的值 。注意和上面的從左到右處理的算法不同,是從右往左掃描 , 但兩個算法計算出來的值相同。(其實這個算法相當於后續遍歷時候先遍歷右子樹)
Scan the given prefix expression from right to left
for each symbol
{
if operand then
push onto stack
if operator then
{
operand1=pop stack
operand2=pop stack
compute operand1 operator operand2
push result onto stack
}
}
return top of stack as result
Applying this algorithm to the example above yields the following:
− × ÷ 15 − 7 + 1 1 3 + 2 + 1 1 =
− × ÷ 15 − 7 + 1 1 3 + 2 2 =
− × ÷ 15 − 7 + 1 1 3 4 =
− × ÷ 15 − 7 2 3 4 =
− × ÷ 15 5 3 4 =
− × 3 3 4 =
− 9 4 =
5
This uses the same expression as before and the algorithm above.
− × ÷ 15 − 7 + 1 1 3 + 2 + 1 1
| Token |
Action |
Stack |
Notes |
| 1 |
Operand |
1 |
Push onto stack. |
| 1 |
Operand |
1 1 |
Push onto stack. |
| + |
Operator |
2 |
Pop the two operands (1, 1), calculate (1 + 1 = 2) and push onto stack. |
| 2 |
Operand |
2 2 |
Push onto stack. |
| + |
Operator |
4 |
Pop the two operands (2, 2), calculate (2 + 2 = 4) and push onto stack. |
| 3 |
Operand |
3 4 |
Push onto stack. |
| 1 |
Operand |
1 3 4 |
Push onto stack. |
| 1 |
Operand |
1 1 3 4 |
Push onto stack. |
| + |
Operator |
2 3 4 |
Pop the two operands (1, 1), calculate (1 + 1 = 2) and push onto stack. |
| 7 |
Operand |
7 2 3 4 |
Push onto stack. |
| − |
Operator |
5 3 4 |
Pop the two operands (7, 2), calculate (7 − 2 = 5) and push onto stack. |
| 15 |
Operand |
15 5 3 4 |
Push onto stack. |
| ÷ |
Operator |
3 3 4 |
Pop the two operands (15, 5), calculate (15 ÷ 5 = 3) and push onto stack. |
| × |
Operator |
9 4 |
Pop the two operands (3, 3), calculate (3 × 3 = 9) and push onto stack. |
| − |
Operator |
5 |
Pop the two operands (9, 4), calculate (9 − 4 = 5) and push onto stack. |
The result is at the top of the stack.
calc_prefix.cpp 代碼實現如下 :
#include<cstdio>
#include<cstring>
#include<iostream>
#include<string>
#include<algorithm>
#include<stack>
using namespace std;
bool is_op(char c)
{
return c=='+' || c=='-' || c=='*' || c=='/';
}
int calc(char op, int l, int r)
{
switch(op)
{
case '+':
return l+r;
case '-':
return l-r;
case '*':
return l*r;
case '/':
return l/r;
}
return 0;
}
int calc_prefix(char* buf)
{
stack<int> st;
int i=strlen(buf)-1;
while(i>=0)
{
printf("%d\n", i);
if(is_op(buf[i]))
{
int l, r;
l=st.top(); st.pop();
r=st.top(); st.pop();
st.push(calc(buf[i], l, r));
--i;
}
else if(isdigit(buf[i]))
{
--i;
while(isdigit(buf[i]))
--i;
st.push(atoi(&buf[i+1]));
}
else
{
//white space
--i;
}
}
cout<<"stack size: "<<st.size()<<endl;
return st.top();
}
int main()
{
char buf[256];
while(gets(buf))
{
cout<<calc_prefix(buf)<<endl;
}
return 0;
}
輸入:
- * / 15 - 7 + 1 1 3 + 2 + 1 1
輸出:
5
參考:
http://en.wikipedia.org/wiki/Polish_notation 及其中文鏈接
