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                 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的结果:

时间: 2024-07-30 17:40:35

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

PAT 线性结构3. 求前缀表达式的值 栈的应用

题目链接: 前缀表达式求值 题解: 同后缀表达式求值思路: 遇到数值则入栈,遇到操作符则从栈中取出最上面的两个数值进行操作,再将结果入栈,最后得到的栈顶元素则为答案. 前缀表达式从后往前遍历即可. 代码: #include<iostream> #include<cstdio> #include<cstring> #include<stack> using namespace std; int op(char a) { if(a=='+'||a=='-'||a

【PAT】2-3 求前缀表达式的值

求值方法: 对于一个前缀表达式的求值而言,首先要从右至左扫描表达式,从右边第一个字符开始判断,如果当前字符是数字则一直到数字串的末尾再记录下来,如果是运算符,则将右边离得最近的两个“数字串”作相应的运算,以此作为一个新的“数字串”并记录下来.一直扫描到表达式的最左端时,最后运算的值也就是表达式的值.例如,前缀表达式“- 1 + 2 3“的求值,扫描到3时,记录下这个数字串,扫描到2时,记录下这个数字串,当扫描到+时,将+右移做相邻两数字串的运算符,记为2+3,结果为5,记录下这个新数字串,并继续

《软件技术基础》实验指导 实验七

排序 实验七 排序 一.实验目的 熟悉各种内部排序算法 能够编写程序显示排序过程中各趟排序的结果 能够编写一些排序的算法 二.实验内容 采用希尔排序方法对顺序表中的证型数据进行排序,设计希尔排序算法并显示每趟排序的结果. 编写一个双向起泡的排序算法,即在排序过程中交替改变扫描方向,同时显示各趟排序的结果. Tips 7.1 希尔排序 https://en.wikipedia.org/wiki/Shellsort 7.2 鸡尾酒排序 https://en.wikipedia.org/wiki/Co

《软件技术基础》实验指导 实验八

查找 实验八 查找 一.实验目的 熟悉线性表.二叉排序树和散列表的查找 能够编写一些查找的算法 二. 实验内容 18个记录的关键字如下,编写分块查找的算法进行查找. 22.12.13.8.9.20.33.42.44.38.24.48.60.58.74.49.86.53 编写一个判别给定的二叉树是否为二叉排序树的算法,设二叉树以二叉链表存储表示,结点的数据域只存放正整数. Tips 8.1 分块查找 http://student.zjzk.cn/course_ware/data_structure

操作系统实验指导书(完整版)

操作系统实验指导书 烟台大学计算机学院 操作系统课程组 2008-9-20 第一部分  操作系统上机指导   Linux操作系统环境: RedHat Enterprise Linux ES release 3 (Taroon Update 1) (2.4.21-9.EL) Red Flag Linux release 4.0 (HOT) (2.4)   登录到系统 常用命令练习: 用root账号(超级用户)注册,口令为computer(注意大小写).注册成功出现#号(超级用户系统提示符,普通用户

# 20182333 2019-2020-1 《数据结构与面向对象程序设计》实验5报告

20182333 2019-2020-1 <数据结构与面向对象程序设计>实验5报告 课程:<程序设计与数据结构> 班级: 1823 姓名: 钱佳禹 学号:20182333 实验教师:王志强 实验日期:2019年10月14日 必修/选修: 必修 1.实验内容 1.Android Stuidio的安装测试: 参考<Java和Android开发学习指南(第二版)(EPUBIT,Java for Android 2nd)>第二十四章: 参考http://www.cnblogs.

20182324 2019-2020-1 《数据结构与面向对象程序设计》实验5报告

20182324 2019-2020-1 <数据结构与面向对象程序设计>实验5报告 课程:<程序设计与数据结构> 班级: 1823 姓名: 殷宇豪 学号: 20182324 实验教师:王志强 实验日期:2019年10月14日 必修/选修: 必修 1.实验内容 1.Android Stuidio的安装测试: 参考<Java和Android开发学习指南(第二版)(EPUBIT,Java for Android 2nd)>第二十四章: 参考http://www.cnblogs

2019-2020-2314《数据结构与面向对象程序设计》实验五报告

学号 2019-2020-2314<数据结构与面向对象程序设计>实验四报告 课程:<程序设计与数据结构> 班级: 1823 姓名: 鞠明翰 学号:20182314 实验教师:王志强 实验日期:2019年10月18日 必修/选修: 必修 1.实验内容 1.1 Android Stuidio的安装测试 参考<Java和Android开发学习指南(第二版)(EPUBIT,Java for Android 2nd)>第二十四章: 参考http://www.cnblogs.com

20182330 2019-2020-1 《数据结构与面向对象程序设计》实验八报告

20182330 2019-2020-1 <数据结构与面向对象程序设计>实验八报告 课程:<程序设计与数据结构> 班级: 1823 姓名: 魏冰妍 学号:20182330 实验教师:王志强 实验日期:2019年11月11日 必修/选修: 必修 1.实验内容 参考教材PP16.1,完成链树LinkedBinaryTree的实现(getRight,contains,toString,preorder,postorder)用JUnit或自己编写驱动类对自己实现的LinkedBinaryT