逆波兰表达式

有一个自定义类型Query类,它可以实现搜索指定字符串的对应行并输出,同时支持&,|和~运算,于是我想通过用户输入字符串从而实现组合运算(包含括号),这时想起了逆波兰表达式

首先明确用户输入的是中缀表示式,但是中缀表达式是适用于人思考运算的,因为需要顾前顾后,但是计算机难以解读(因为一般是从左向右解析字符串的),并且需要考虑括号,而逆波兰表达式可以没有括号并且考虑了运算符优先级

一个简单的栗子:$1+(2+3) \times 5$=>$1 2 3 + 5 \times +$

逆波兰表达式如何运算:从左到右依次压栈,遇到运算符,取出栈顶两个操作数进行运算再放回去 ,最后输出栈顶

中缀转后缀

转化规则如下:

  • (:push
  • ):)不push,pop栈顶直到遇到(或栈空
  • 运算符:pop优先级>=当前运算符的元素直到遇到(或栈空
  • 运算元:不push直接输出
  • 空格:直接跳过
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
std::map<char,unsigned char> priority_=
{
{'|',0},{'&',0},
{'~',1},
{'(',2},{')',2}
};

bool is_Queryoperators(char op)
{
if(op=='&' || op=='|' || op=='~') return true;
else return false;
}

bool is_Queryoperands(char op)
{
if(op!=' ' && op!='(' && op!=')' && !is_Queryoperators(op)) return true;
else return false;
}

bool is_unary(char op)
{
if(op=='~') return true;
else return false;
}

bool is_binary(char op)
{
if(op=='&' || op=='|') return true;
else return false;
}

std::string get_reverse_polish_expr(std::string const& str)
{
auto len=str.length();
stack<char> operators;
std::string res;
for(std::size_t i=0;i!=len;++i)
{
auto c=str[i];
if(c=='(')
{
operators.push(c);
}else if(c==')'){
while(!operators.empty() && operators.top()!='(')
{
res+=operators.top();operators.pop();res+=" ";
}
operators.pop();
}else if(c==' '){
continue;
}else if(is_Queryoperators(c)){
while(!operators.empty() && operators.top()!='(' && priority_[operators.top()] >= priority_[c])
{
res+=operators.top();operators.pop();res+=" ";
}
operators.push(c);
}else if(is_Queryoperands(c)){
res+=c;
while(i+1<len)
{
auto next=str[i+1];
if(is_Queryoperands(next))
{
res+=next;++i;
}
else
{
res+=" ";break;
}
}
if(i+1 == len) res+=" ";
}
}

while(!operators.empty())
{
res+=operators.top();operators.pop();res+=" ";
}

return res;
}

计算后缀表达式

先将得到的后缀表达式按” “分割成字符串向量,然后逐一push按上述方法计算即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
typedef std::vector<std::string> StringVector;

StringVector split(std::string str)
{
StringVector contents;
std::string::size_type loc=str.find(" ");
while(loc != std::string::npos)
{
contents.emplace_back(str.substr(0,loc));
str=str.substr(loc+1);
loc=str.find(" ");
}
if(!str.empty()) contents.emplace_back(str);

return contents;
}

Query eval(std::string expr)
{
auto ops=split(get_reverse_polish_expr(expr));
stack<Query> calc;
for(auto& op : ops)
{
auto op_=op[0];
if(is_unary(op_))
{
auto tmp=calc.top();calc.pop();
calc.push(~tmp);
}else if(is_binary(op_))
{
auto rhs=calc.top();calc.pop();
auto lhs=calc.top();calc.pop();
switch(op_)
{
case '&':calc.push(lhs & rhs);break;
case '|':calc.push(lhs | rhs);break;
}
}else
{
calc.push(Query(op));
}
}

return calc.top();
}