波兰表示法(前缀表示法)
波兰表示法, 也叫前缀表示法。
运算波兰表达式时,无需记住运算的层次,只需要直接寻找第一个运算的操作符。以二元运算为例,从左至右读入表达式,遇到一个操作符后跟随两个操作数时,则计算之,然后将结果作为操作数替换这个操作符和两个操作数;重复此步骤,直至所有操作符处理完毕。因为在正确的前缀表达式中,操作数必然比操作符多一个,所以必然能找到一个操作符符合运算条件;而替换时,两个操作数和一个操作符替换为一个操作数,所以减少了各一个操作符和操作数,仍然可以迭代运算直至计算整个式子。多元运算也类似,遇到足够的操作数即产生运算,迭代直至完成。迭代结束的条件由表达式的正确性来保证。下面是一个例子,演示了每一步的运算顺序:
其特点是操作符置于操作数的前面,因此也称做前缀表示法。如果操作符的元数(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 及其中文链接