进阶实验3-3.1 求前缀表达式的值 (25分)
算术表达式有前缀表示法、中缀表示法和后缀表示法等形式。前缀表达式指二元运算符位于两个运算数之前,例如2+3*(7-4)+8/4的前缀表达式是:+ + 2 * 3 - 7 4 / 8 4。请设计程序计算前缀表达式的结果值。
输入格式:
输入在一行内给出不超过30个字符的前缀表达式,只包含+、-、*、/以及运算数,不同对象(运算数、运算符号)之间以空格分隔。
输出格式:
输出前缀表达式的运算结果,保留小数点后1位,或错误信息ERROR。
输入样例: + + 2 * 3 - 7 4 / 8 4
输出样例: 13.0
做这道题的时候,我是先实现运算数均为单个数字(例如3)的情况,没有通过所有测试点;在此基础上,实现运算数存在连续数字(例如123)的情况,也没有通过所有测试点;又在此基础上,再实现运算数存在浮点数(例如123.55)的情况,通过了所有测试点。在连续数字和浮点数情况中,我是以字符单独输入后再组装成一个整数或者浮点数,最后代码写得有点庞大,也有点乱。这里直接写写解题思路吧,参考了weixin_42104573的一篇博客。
原文链接:https://blog.youkuaiyun.com/weixin_42104573/article/details/80431862?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
前缀表达式求值解题思路:
从右到左扫描前缀表达式,从右边第一个字符开始判断,如果当前字符(或字符串)为数字,则压入栈内;如果是运算符,则将栈顶两个元素弹出栈外并作相应运算,再将结果压入栈内。当前缀表达式扫描结束时,栈里的就是中缀表达式运算的最终结果。
以+ + 2 * 3 - 7 4 / 8 4为例:
从右向左进行扫描
读入运算数4,压栈;
读入运算数8,压栈;
读入运算符/,将栈顶两个元素8和4弹出,后入栈的数字先出栈,做分子,先入栈的数字后出栈,做分母,8/4=2,将结果2压栈;
读入运算数4,压栈;
读入运算数7,压栈;
读入运算符-,将栈顶两个元素7和4弹出,7-4=3,将结果3压栈;
读入运算数3,压栈;
读入运算符*,将栈顶两个元素3和3弹出,3*3=9,将结果9压栈;
读入运算数2,压栈;
读入运算符+,将栈顶两个元素2和9弹出,2+9=11,将结果11压栈;
读入运算符+,将栈顶两个元素11和2弹出,11+2=13,将结果13压栈;扫描完毕后,栈内元素为13,即为结果,输出。
20200825补充:
按照上述思路,用C++语言写了代码:
#include<iostream>
using namespace std;
struct stack
{
double* data;
int Top;
int MAXSIZE;
};
typedef struct stack* Stack;
Stack CreateStack(int m)
{
Stack S = new struct stack;
S->MAXSIZE = m;
S->Top = -1;
S->data = new double[S->MAXSIZE];
return S;
}
void Push(Stack S, double X)
{
S->data[++S->Top] = X;
}
double Pop(Stack S)
{
return S->data[S->Top--];
}
double Top(Stack S)
{
return S->data[S->Top];
}
bool IsEmpty(Stack S)
{
if (S->Top == -1) return true;
else return false;
}
bool IsFull(Stack S)
{
if (S->Top == S->MAXSIZE - 1)return true;
else return false;
}
int main()
{
char* s = new char[62];
char* sr = new char[10];
char c;
cin >> c;
int i = 0, j = 0;
while (c != '\n')
{
s[i] = c;
scanf("%c", &c);
i++;
}
int n = i;
int floa = 0; //操作数有小数部分的情况floa=1
double m = 0; //m是读入的完整的操作数,m压栈
int nz = 0, nx = 0; //nz记录整数部分数字个数,nx记录小数部分数字个数
double ret = 0;
int error = 0; //出错error=1(除数=0情况出错)
Stack S = CreateStack(30);
for (i = n - 1; i >= 0; i--)
{
floa = 0;
if (s[i] >= '0'&&s[i] <= '9')
{
j = 0;
m = 0; nz = 0, nx = 0;
while (s[i - 1] >= '0'&&s[i - 1] <= '9')
{
sr[j] = s[i];
j++;
i--;
}
sr[j] = s[i];
if (s[i - 1] == '.')
{
floa = 1;
nx = j + 1;
sr[++j] = '.';
j++;
i--;
while (s[i - 1] >= '0'&&s[i - 1] <= '9')
{
sr[j] = s[i];
j++;
i--;
}
sr[j] = s[i];
nz = j - nx - 1;
}
if (floa == 0)
{
nz = j + 1;
nx = 0;
}
for (int k = 0; k < nz; j--, k++) //求整数部分
{
m = 10 * m + sr[j] - '0';
}
j = j - 2; double t = 0.1;
for (int k = 0; k < nx; k++, j--) //求小数部分
{
m = m + t * (sr[j] - '0');
t = t * 0.1;
}
if (s[i - 1] == '+') //处理操作数为+25的情况
{
i--;
}
if (s[i - 1] == '-') //处理操作数为-25的情况
{
m = -m;
i--;
}
Push(S, m); //操作数压栈
}
else if (s[i] == '+')
{
double oper1 = Pop(S);
double oper2 = Pop(S);
ret = oper1 + oper2;
Push(S, ret);
}
else if (s[i] == '-')
{
double oper1 = Pop(S);
double oper2 = Pop(S);
ret = oper1 - oper2;
Push(S, ret);
}
else if (s[i] == '*')
{
double oper1 = Pop(S);
double oper2 = Pop(S);
ret = oper1 * oper2;
Push(S, ret);
}
else if (s[i] == '/')
{
double oper1 = Pop(S);
double oper2 = Pop(S);
if (oper2 == 0) { cout << "ERROR"; error = 1; break; }
else {
ret = oper1 / oper2;
Push(S, ret);
}
}
}
if (error == 0) printf("%.1f\n", Pop(S));
return 0;
}