中国大学MOOC-数据结构基础习题集、02-3、求前缀表达式的值

首先粘一下题目:

算术表达式有前缀表示法、中缀表示法和后缀表示法等形式。前缀表达式指二元运算符位于两个运算数之前,例如2+3*(7-4)+8/4的前缀表达式是:+ + 2 * 3 - 7 4 / 8 4。请设计程序计算前缀表达式的结果值。

输入格式说明:

输入在一行内给出不超过30个字符的前缀表达式,只包含+、-、*、\以及运算数,不同对象(运算数、运算符号)之间以空格分隔。

输出格式说明:

输出前缀表达式的运算结果,精确到小数点后1位,或错误信息“ERROR”。

样例输入与输出:

序号 输入 输出
1
+ + 2 * 3 - 7 4 / 8 4
13.0
2
/ -25 + * - 2 3 4 / 8 4
12.5
3
/ 5 + * - 2 3 4 / 8 2
ERROR
4
+10.23
10.2

这里就不按照惯例给出建议的测试用例了,直接用题目中给的4个就可以了。

先说一下我的解题思路吧:

1. 首先要处理输入的数据,这里用到的数据结构有string data和stack<double>myStack,stack<int>intStack。string data要用getline()函数读入一整行字符串,如果直接用cin的话遇到空格读入会停止的。myStack用来存放中间结果,intStack用来存放读入“数字”字符。len是输入字符串的长度,dotPos记录了小数点的位置。

1     string data;
2     stack<double> myStack;
3     stack<int> intStack;
4     int len = data.size();
5     int dotPos = 0;
6     getline(cin, data);

2. 接下来要用到for循环,从后向前的处理每一个字符。

1    for (int i=len-1; i!=-1; i--)
2     {

3. 第一个if语句,用来判断是不是小数点,并且更新小数点位置dotPos。

1         if(data[i]=='.')
2         {
3             dotPos = intStack.size();
4             continue;
5         }

4. 第二个if语句,用来判断是不是+ - * /,并且如果要是+ -还要考虑他们是一元运算符(表示正负),还是二元运算符(表示加减)。

1         if(data[i]=='+' || data[i]=='-' || data[i]=='*' || data[i]=='/')
2         {

4.1 如果是一元运算符-(表示负),首先要从intStack中弹出全部的数字,把它们“拼接”成一个完整的整数(见while循环)。同时还要考虑这个数是整数,还是小数,那么之前的dotPos就用到了(见if语句)。只需要判断dotPos是不是0就可以了:如果是0,说明它是一个整数。如果不是0,说明它是一个浮点数。将小数点向前移动dotPos位,也就是除以10的dotPos次方。同时把这个数字乘以-1,压入myStack栈中。具体的代码如下:

 1             if(data[i]=='-' && intStack.size()!=0)
 2             {
 3                 int icount = 0;
 4                 double itemp = 0;
 5                 int ilen = intStack.size();
 6                 while(intStack.size() != 0)
 7                 {
 8                     int inttemp = intStack.top();
 9                     intStack.pop();
10                     itemp += pow(10, ilen - 1 - icount) * inttemp;
11                     icount ++;
12                 }
13                 itemp *= -1;
14                 if(dotPos == 0)
15                     myStack.push(itemp);
16                 else
17                 {
18                     myStack.push(itemp / pow(10, dotPos));
19                     dotPos = 0;
20                 }
21                 continue;
22             }

4.2 判断是一元运算符+(表示正),方法和上面几乎完全相同,只不过是少乘以一个-1就可以了,代码如下:

 1             else if(data[i]=='+' && intStack.size()!=0)
 2             {
 3                 int icount = 0;
 4                 double itemp = 0;
 5                 int ilen = intStack.size();
 6                 while(intStack.size() != 0)
 7                 {
 8                     int inttemp = intStack.top();
 9                     intStack.pop();
10                     itemp += pow(10, ilen - 1 - icount) * inttemp;
11                     icount ++;
12                 }
13                 if(dotPos == 0)
14                     myStack.push(itemp);
15                 else
16                 {
17                     myStack.push(itemp / pow(10, dotPos));
18                     dotPos = 0;
19                 }
20                 continue;
21             }

  Tips:这里鼓励大家,尝试把两段代码捏在一起,这样能节约代码的行数。不妨试试看。

4.3 接下来就是判断二元运算符了,因为二元运算符必须要两个操作数,因此如果myStack栈中的数字少于两个,那么肯定就是ERROR了。同样,如果除法运算的除数是0,那肯定也是ERROR。进行+ - * /之后,不要忘记把结果压入myStack栈中。这部分比较简单,代码如下:

 1             else if(myStack.size() < 2)
 2             {
 3                 cout << "ERROR" << endl;
 4                 return 0;
 5             }
 6             double a = myStack.top();
 7             myStack.pop();
 8             double b = myStack.top();
 9             myStack.pop();
10             double r = 0;
11             switch(data[i])
12             {
13             case '+':
14                 r = a + b;
15                 break;
16             case '-':
17                 r = a - b;
18                 break;
19             case '*':
20                 r = a * b;
21                 break;
22             case '/':
23                 r = a / b;
24                 {
25                     if (b != 0)
26                         r = a / b;
27                     else
28                     {
29                         cout << "ERROR" << endl;
30                         return 0;
31                     }
32                 }
33                 break;
34             }
35             myStack.push(r);
36             continue;
37         }            

5. 第3个if语句,用来判断是不是空格,即' ',如果是空格的话,之前intStack栈中的数字,要全部弹出,组成一个新的数字,压入myStack栈中。方法其实上面已经有了。可以自己尝试写一下。代码如下:

 1         if(data[i]==' ')
 2         {
 3             int icount = 0;
 4             double itemp = 0;
 5             int ilen = intStack.size();
 6             while(intStack.size() != 0)
 7             {
 8                 int inttemp = intStack.top();
 9                 intStack.pop();
10                 itemp += pow(10, ilen - 1 - icount) * inttemp;
11                 icount ++;
12             }
13             if(ilen != 0)
14             {
15                 if(dotPos == 0)
16                     myStack.push(itemp);
17                 else
18                 {
19                     myStack.push(itemp / pow(10, dotPos));
20                     dotPos = 0;
21                 }
22             }
23             continue;
24         }

6. 第4个if语句,用来判断是不是'0'到'9',如果是的话,压入intStack栈中。注意压栈的时候要减掉'0'哦。因为data[i]可是字符。

1         if(data[i]>='0' && data[i]<='9')
2         {
3             intStack.push(data[i]-'0');
4             continue;
5         }
6     }

7. 输出结果,就是myStack栈中的那一个元素了。

1     printf("%.1lf", myStack.top());
2     return 0;
3 }

8. 完整代码如下:

  1 #include <cstdio>
  2 #include <cstdlib>
  3 #include <iostream>
  4 #include <iomanip>
  5 #include <stack>
  6 #include <cmath>
  7 
  8 using namespace std;
  9 int main()
 10 {
 11     string data;
 12     stack<double> myStack;
 13     stack<int> intStack;
 14     int len = data.size();
 15     int dotPos = 0;
 16     getline(cin, data);
 17     for (int i=len-1; i!=-1; i--)
 18     {
 19         if(data[i]=='.')
 20         {
 21             dotPos = intStack.size();
 22             continue;
 23         }
 24         if(data[i]=='+' || data[i]=='-' || data[i]=='*' || data[i]=='/')
 25         {
 26             if(data[i]=='-' && intStack.size()!=0)
 27             {
 28                 int icount = 0;
 29                 double itemp = 0;
 30                 int ilen = intStack.size();
 31                 while(intStack.size() != 0)
 32                 {
 33                     int inttemp = intStack.top();
 34                     intStack.pop();
 35                     itemp += pow(10, ilen - 1 - icount) * inttemp;
 36                     icount ++;
 37                 }
 38                 itemp *= -1;
 39                 if(dotPos == 0)
 40                     myStack.push(itemp);
 41                 else
 42                 {
 43                     myStack.push(itemp / pow(10, dotPos));
 44                     dotPos = 0;
 45                 }
 46                 continue;
 47             }
 48             else if(data[i]=='+' && intStack.size()!=0)
 49             {
 50                 int icount = 0;
 51                 double itemp = 0;
 52                 int ilen = intStack.size();
 53                 while(intStack.size() != 0)
 54                 {
 55                     int inttemp = intStack.top();
 56                     intStack.pop();
 57                     itemp += pow(10, ilen - 1 - icount) * inttemp;
 58                     icount ++;
 59                 }
 60                 if(dotPos == 0)
 61                     myStack.push(itemp);
 62                 else
 63                 {
 64                     myStack.push(itemp / pow(10, dotPos));
 65                     dotPos = 0;
 66                 }
 67                 continue;
 68             }
 69             else if(myStack.size() < 2)
 70             {
 71                 cout << "ERROR" << endl;
 72                 return 0;
 73             }
 74             double a = myStack.top();
 75             myStack.pop();
 76             double b = myStack.top();
 77             myStack.pop();
 78             double r = 0;
 79             switch(data[i])
 80             {
 81             case '+':
 82                 r = a + b;
 83                 break;
 84             case '-':
 85                 r = a - b;
 86                 break;
 87             case '*':
 88                 r = a * b;
 89                 break;
 90             case '/':
 91                 r = a / b;
 92                 {
 93                     if (b != 0)
 94                         r = a / b;
 95                     else
 96                     {
 97                         cout << "ERROR" << endl;
 98                         return 0;
 99                     }
100                 }
101                 break;
102             }
103             myStack.push(r);
104             continue;
105         }
106         if(data[i]==' ')
107         {
108             int icount = 0;
109             double itemp = 0;
110             int ilen = intStack.size();
111             while(intStack.size() != 0)
112             {
113                 int inttemp = intStack.top();
114                 intStack.pop();
115                 itemp += pow(10, ilen - 1 - icount) * inttemp;
116                 icount ++;
117             }
118             if(ilen != 0)
119             {
120                 if(dotPos == 0)
121                     myStack.push(itemp);
122                 else
123                 {
124                     myStack.push(itemp / pow(10, dotPos));
125                     dotPos = 0;
126                 }
127             }
128             continue;
129         }
130         if(data[i]>='0' && data[i]<='9')
131         {
132             intStack.push(data[i]-'0');
133             continue;
134         }
135     }
136     printf("%.1lf", myStack.top());
137     return 0;
138 }

个人分析:

  按照老师的说法,这是一道可以尝试挑战一下自己的题。测试用例还是比较简单的,基本上给的4个都能过的话,肯定能AC。毕竟限制了30个字符的大小,不像PAT1074(即MOOC作业2-1)数据量那么大。

最后粘一下AC的结果:

 

posted @ 2014-12-18 16:11  聪明的聪聪  阅读(1050)  评论(2编辑  收藏  举报