首页 > 代码库 > PAT-《数据结构学习与实验指导》实验项目集-3-07(MOOC2-3)求前缀表达式的值

PAT-《数据结构学习与实验指导》实验项目集-3-07(MOOC2-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                 else17                 {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                 else16                 {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                     else28                     {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                 else18                 {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                 else123                 {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的结果:

 

PAT-《数据结构学习与实验指导》实验项目集-3-07(MOOC2-3)求前缀表达式的值