数据结构习题:进阶实验3-3.1 求前缀表达式的值 (25分)

进阶实验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;
}

在C语言中,将中缀表达式转换为后缀表达式也称为逆波兰表示(Reverse Polish Notation,RPN),通常会通过栈的数据结构来实现。这里是一个简单的步骤描述: 1. 创建一个空栈一个结果数组。 2. 遍历中缀表达式的每个字符: - 如果遇到数字,直接添加到结果数组。 - 如果遇到算符,按照优先级处理: a. 先进栈:如果当前算符的优先级低于栈顶算符,则将栈顶算符压入结果数组,并弹出栈顶元素。 b. 后进:如果当前算符的优先级高于或等于栈顶算符,或栈为空,则将当前算符压入栈。 3. 当遍历完所有字符后,栈中剩余的算符依次压入结果数组。 4. 结果数组就是后缀表达式。 下面是一个简化的C语言函数示例,用于转换单个操作数的加减乘除: ```c #include <stdio.h> #include <stdlib.h> char* infixToPostfix(char* infix) { stack_t *s = (stack_t*)malloc(sizeof(stack_t)); char postfix[100]; int i, j = 0; const char* operators = "+-*/"; for (i = 0; infix[i] != &#39;\0&#39;; i++) { if (isdigit(infix[i])) { // 数字直接加入后缀 postfix[j++] = infix[i]; } else if (strchr(operators, infix[i]) != NULL) { // 算符 while (s->top && strchr(operators, s->top) && precedence(s->top) >= precedence(infix[i])) { postfix[j++] = s->top; s->top = s->data[s->size - 1]; // 弹出栈顶元素 s->size--; } s->top = infix[i]; // 将算符压入栈 } else if (infix[i] == &#39; &#39;) { // 忽略空格 continue; } } while (s->top) { postfix[j++] = s->top; s->top = s->data[s->size - 1]; s->size--; } postfix[j] = &#39;\0&#39;; free(s->data); free(s); return postfix; } // 辅助函数,用于比较算符的优先级 int precedence(char op) { switch (op) { case &#39;+&#39;: case &#39;-&#39;: return 1; case &#39;*&#39;: case &#39;/&#39;: return 2; default: return 0; } } // 示例用法 int main() { char infix[] = "A+B*C"; printf("Infix: %s\n", infix); char* postfix = infixToPostfix(infix); printf("Postfix: %s\n", postfix); return 0; } ``` 请注意,这个示例仅适用于最简单的四则算。实际应用中,还需要处理括号以及更复杂的表达式。完整的实现可能需要更复杂的算法,例如Shunting Yard算法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值