【数据结构】栈与队列 Part2:栈的应用之表达式转换

这里主要记录:中缀表达式与后缀表达式的转换。

中缀表达式,即就是常用于人类理解的一般表达式。

后缀表达式,即就是常用于机器读取的特殊表达式。

此外还有前缀表达式。

给出中缀表达式的例子:9 + ( 3 - 1 ) * 3 + 10 / 2

给出后缀表达式的例子:9 3 1 - 3 * + 10 2 / +

给出前缀表达式的例子:+ + * -  3 1 3 9 / 2 10

实际上这三者给出的是同一个计算式。

关于各种表达式的运算规则,可参阅 前缀、中缀、后缀表达式(逆波兰表达式),这篇文章同时也给出了三种表达式的转换方法。

下面给出一个前缀表达式的计算代码,使用了递归方式运算。

注:1.atof函数是在头文件#include<stdlib.h>中将char*转化为浮点数的函数。

      2.static声明是指在程序运行过程中只声明一次,之后遇到该语句时跳过。

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 double cal()
 4 {
 5     static char buffer[64];
 6     scanf("%s", buffer);
 7     switch(buffer[0])
 8     {
 9         case '+':
10             return cal() + cal();
11         case '-':
12             return cal() - cal();
13         case '*':
14             return cal() * cal();
15         case '/':
16             return cal() / cal();
17         default:
18             return atof(buffer);
19     }
20 }
21 int main()
22 {
23     printf("%lf" "\n", cal());
24     return 0;
25 }

下面给出利用栈结构将中缀表达式转化为后缀表达式的思路,这也参阅了上文提到的文章。

转化为前缀表达式只需将后缀表达式的输出结果反序即可。

1.创建栈s1,保存运算符;创建栈s2,保存中间结果。

2.读取中缀表达式的顺序是由左至右。

3.若输入为数据,压入s2。

4.若输入为运算符:

    1)若s1为空或s1栈顶元素为'(',直接入栈。

    2)若s1栈顶元素的优先级比输入的运算符优先级更低或二者相同,直接入栈。(注:优先级与一般相同,即'+'='-'<'*'='/')

    3)若s1栈顶元素的优先级比输入的运算符优先级更高,将s1栈顶元素放入s2,重复执行4.。

5.若输入为括号:

    1)左括号直接压入s1。

    2)右括号则一直弹出到栈顶元素为左括号为止,然后将两个括号销毁。

6.不断重复至输入结束,将s1剩余的运算符放入s2.

7.依次弹出s2中的结果逆序输出后就可以得到后缀表达式了。

对思路进行程序实现: 

 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<stdlib.h>
 4 #include<algorithm>
 5 #include<map>
 6 #include<stack>
 7 #include<queue>
 8 
 9 using namespace std;
10 
11 int level(string buffer){
12     switch (buffer[0]) {
13         case '+': return 1;
14         case '-': return 1;
15         case '*': return 2;
16         case '/': return 2;
17         default:  return 0;
18     }
19 }
20 
21 int main(){
22     stack<string> s1;
23     stack<string> s2;
24     string buffer;
25     char a;
26 //    scanf("%s",&buffer[0]);
27     cin>>buffer;
28     a=getchar();
29     while (1){
30         if (buffer[0]>='0'&&buffer[0]<='9'){
31             s2.push(buffer);
32         }
33         if (buffer[0]=='+'||
34             buffer[0]=='-'||
35             buffer[0]=='*'||
36             buffer[0]=='/'){
37             if (s1.empty()==1||
38                 s1.top()=="("){
39                 s1.push(buffer);
40             }
41             else{
42                 if (level(s1.top())<=level(buffer)){
43                     s1.push(buffer);
44                 }
45                 else{
46                     while (s1.empty()!=1&&
47                            s1.top()!="("&&
48                            level(s1.top())>level(buffer)){
49                         s2.push(s1.top());
50                         s1.pop();
51                     }
52                     s1.push(buffer);
53                 }
54             }
55         }
56         if (buffer[0]=='('||
57             buffer[0]==')'){
58             if (buffer[0]=='('){
59                 s1.push(buffer);
60             }
61             if (buffer[0]==')'){
62                 while (s1.empty()!=1&&
63 //                       s1.top()[0]!='('){
64                        s1.top()!="("){
65                     s2.push(s1.top());
66                     s1.pop();
67                 }
68                 s1.pop();
69             }
70         }
71         if (a=='\n'){break;}
72 //        scanf("%s",&buffer[0]);
73         cin>>buffer;
74         a=getchar();
75     }
76     while (s1.empty()!=1){
77         s2.push(s1.top());
78         s1.pop();
79     }
80     while (s2.empty()!=1){
81         s1.push(s2.top());
82         s2.pop();
83     }
84     while (s1.empty()!=1){
85         printf("%s",s1.top().c_str());
86         printf(" ");
87         s1.pop();
88     }
89     return 0;
90 }

 需要注意的有三点:

1.用注释内的部分scanf输入时,必须同时使用s1.top()[0]!='('作为结束循环的条件,否则会出现问题,原因尚不明确。

2.用printf输出string类型时,要记为string.c_str(),否则无法使用。

3.这种输入方式无法兼容负数。

(4.果然还是cin和cout好用多了)

 

P.S.

ios::sync_with_stdio(false);

由于scanf速度比cin快很多,常常在对时间要求很高的时候不得不使用。

但是个人认为cin比scanf好用的多,不容易出bug,因此咨询大佬后发现,只要在主函数的第一句加入上面这一行代码,即可提高cin的速度。

(好像是取消同步之类的)但是也具有副作用,即使用了这个代码后就不可以使用scanf函数输入,否则会出现输入顺序错乱的情况。

posted @ 2018-12-03 16:32  ParallelParadox  阅读(165)  评论(0编辑  收藏  举报