1.后缀表达式
后缀表达式又名逆波兰表达式,相对于中缀表达式的最大优点是不需要考虑优先级规则。
后缀表达式的计算可以用到栈数据结构,下面给出计算过程实例(来自点击打开链接):
-
计算
5 1 2 + 4 × + 3 −的值
-
Input Action Stack Notes 5 Operand 5 Push onto stack. 1 Operand 1 5 Push onto stack. 2 Operand 2 1 5 Push onto stack. + Operator 3 5 Pop the two operands (1, 2), calculate (1 + 2 = 3) and push onto stack. 4 Operand 4 3 5 Push onto stack. × Operator 12 5 Pop the two operands (3, 4), calculate (3 * 4 = 12) and push onto stack. + Operator 17 Pop the two operands (5, 12), calculate (5 + 12 = 17) and push onto stack. 3 Operand 3 17 Push onto stack. − Operator 14 Pop the two operands (17, 3), calculate (17 - 3 = 14) and push onto stack. Result 14
代码实现
#include <stdlib.h>
#include <iostream>
#include <string>
#include <vector>
#include <stack>
int postfix_calc(std::vector<std::string> &vec)
{
std::stack<double> st;
double a, b;
for( auto str: vec)
{
if( str == "+" || str == "*" || str == "-")
{
a = st.top();
st.pop();
b = st.top();
st.pop();
switch(str[0]){
case '+':
st.push(a+b);
break;
case '-':
st.push(b-a);
break;
case '*':
st.push(a*b);
break;
default:
break;
}
}
else
{
st.push(atoi(str.c_str()));
}
}
return st.top();
}
int main(int argc, char *argv[])
{
std::vector<std::string> vec(argv+1, argv+argc);
std::cout<<postfix_calc(vec)<<std::endl;
return 0;
}
Input | Action | Stack | Notes |
---|---|---|---|
5 | Operand | 5 | Push onto stack. |
1 | Operand | 1 5 | Push onto stack. |
2 | Operand | 2 1 5 | Push onto stack. |
+ | Operator | 3 5 | Pop the two operands (1, 2), calculate (1 + 2 = 3) and push onto stack. |
4 | Operand | 4 3 5 | Push onto stack. |
× | Operator | 12 5 | Pop the two operands (3, 4), calculate (3 * 4 = 12) and push onto stack. |
+ | Operator | 17 | Pop the two operands (5, 12), calculate (5 + 12 = 17) and push onto stack. |
3 | Operand | 3 17 | Push onto stack. |
− | Operator | 14 | Pop the two operands (17, 3), calculate (17 - 3 = 14) and push onto stack. |
Result | 14 |
#include <stdlib.h>
#include <iostream>
#include <string>
#include <vector>
#include <stack>
int postfix_calc(std::vector<std::string> &vec)
{
std::stack<double> st;
double a, b;
for( auto str: vec)
{
if( str == "+" || str == "*" || str == "-")
{
a = st.top();
st.pop();
b = st.top();
st.pop();
switch(str[0]){
case '+':
st.push(a+b);
break;
case '-':
st.push(b-a);
break;
case '*':
st.push(a*b);
break;
default:
break;
}
}
else
{
st.push(atoi(str.c_str()));
}
}
return st.top();
}
int main(int argc, char *argv[])
{
std::vector<std::string> vec(argv+1, argv+argc);
std::cout<<postfix_calc(vec)<<std::endl;
return 0;
}
2.中缀表达式转后缀表达式(调度场算法)
算法流程如下(来自
调度场算法)
输入 | 动作 | 输出 (逆波兰表示法) | 运算符栈 | 提示 |
---|---|---|---|---|
3 | 将符号加入输出队列 | 3 | ||
+ | 将符号压入操作符堆栈 | 3 | + | |
4 | 将符号加入输出队列 | 3 4 | + | |
* | 将符号压入操作符堆栈 | 3 4 | * + | *号的优先级高于+号 |
2 | 将符号加入输出队列 | 3 4 2 | * + | |
/ | 将堆栈中元素弹出,加入输出队列 | 3 4 2 * | + | /号和*号优先级相同 |
将符号压入操作符堆栈 | 3 4 2 * | / + | /号的优先级高于+号 | |
( | 将符号压入操作符堆栈 | 3 4 2 * | ( / + | |
1 | 将符号加入输出队列 | 3 4 2 * 1 | ( / + | |
− | 将符号压入操作符堆栈 | 3 4 2 * 1 | − ( / + | |
5 | 将符号加入输出队列 | 3 4 2 * 1 5 | − ( / + | |
) | 将堆栈中元素弹出,加入输出队列 | 3 4 2 * 1 5 − | ( / + | 循环直到找到(号 |
将堆栈元素弹出 | 3 4 2 * 1 5 − | / + | 括号匹配结束 | |
^ | 将符号压入操作符堆栈 | 3 4 2 * 1 5 − | ^ / + | ^号的优先级高于/号 |
2 | 将符号加入输出队列 | 3 4 2 * 1 5 − 2 | ^ / + | |
^ | 将符号压入操作符堆栈 | 3 4 2 * 1 5 − 2 | ^ ^ / + | ^号为从右至左求值 |
3 | 将符号加入输出队列 | 3 4 2 * 1 5 − 2 3 | ^ ^ / + | |
END | 将栈中所有数据加入输出队列 | 3 4 2 * 1 5 − 2 3 ^ ^ / + |
代码如下:
#include <iostream>
#include <stack>
#include <string>
#include <vector>
#include <stdlib.h>
inline bool is_operator(const std::string &str)
{
return (str=="+") || (str=="-") || (str=="*") \
||(str=="/");
}
inline int get_op_level(const char ch)
{
switch(ch)
{
case '*':
case '/':
return 3;
case '+':
case '-':
return 2;
}
return 1;
}
/*
*@brief 调度场算法中缀表达式转后缀表达式
*@param 输入的中缀表达式
@return 返回后缀表达式
*/
std::vector<std::string> shutting_yard(std::vector<std::string> &input)
{
std::vector<std::string> ret;
std::stack<std::string> st;
for( auto str: input )
{
if( is_operator(str) )
{
while( ! st.empty() )
{
std::string pre= st.top();
if( is_operator(pre) && (get_op_level(str[0]) <= get_op_level(pre[0])) )
{
ret.push_back(pre);
st.pop();
}
else
{
break;
}
}
st.push(str);
}
else if( str == "(" )
{
st.push(str);
}
else if( str == ")" )
{
//pop stack still find '('
while( st.top() != "(")
{
ret.push_back(st.top());
st.pop();
}
st.pop(); //pop "("
}
else // number , put to output
{
ret.push_back(str);
}
}
while( !st.empty() )
{
ret.push_back(st.top());
st.pop();
}
return ret;
}
int main(int argc, char *argv[])
{
std::vector<std::string> vec(argv+1, argv+argc);
std::vector<std::string> ret = shutting_yard(vec);
for(auto str: ret)
{
std::cout<<str<<" ";
}
std::cout<<std::endl;
return 0;
}