中国大学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的结果: