表达式求值问题

本文介绍了如何使用C++编程实现中缀表达式到后缀表达式的转换以及后缀表达式的求值过程,涉及到顺序栈存储结构,包括运算符栈和操作数栈的操作,如进栈、出栈、取栈顶元素等。通过转换成后缀表达式,简化了运算符的优先级处理,使得求值变得直观。
摘要由CSDN通过智能技术生成

问题描述

       这里限定的表达式求值问题是: 用户输入一个包含“+”、“-”、“*”、“/”、正整数和圆括号的合法数学表达式,计算该表达式的运算结果。本问题采用顺序栈存储结构。

算术表达式求值过程是: STEP 1:先将算术表达式转换成后缀表达式。STEP 2:然后对该后缀表达式求值。

(1)中缀表达式exp ==》后缀表达式postexp伪代码如下

初始化运算符栈op;
将'='进栈;
从exp读取字符ch;
while (ch!='\0')
{   if (ch不为运算符)
   将后续的所有数字均依次存放到postexp中,并以字符'#'标志数值串结束;
     else 
         switch(Precede(op栈顶运算符,ch))
         {
         case '<':   //栈顶运算符优先级低
 	  将ch进栈;  从exp读取下字符ch;  break;
         case '=':   //只有栈顶运算符为'(',ch为')'的情况
	 退栈; 从exp读取下字符ch; break;
         case '>':    //栈顶运算符应先执行,所以出栈并存放到postexp中
	 退栈运算符并将其存放到postexp中; break;
        }
}
若字符串exp扫描完毕,则将运算符栈op中'='之前的所有运算符依次出栈并存放到postexp中。最后得到后缀表达式postexp; 

(2)对后缀表达式postexp求值伪代码如下

while (从postexp读取字符ch,ch!='\0')
{    若ch为数字,将后续的所有数字构成一个整数存放到数值栈st中。
     若ch为“+”,则从数值栈st中退栈两个运算数,相加后进栈st中。
     若ch为“-”,则从数值栈st中退栈两个运算数,相减后进栈st中。
     若ch为“*”,则从数值栈st中退栈两个运算数,相乘后进栈st中。
     若ch为“/”,则从数值栈st中退栈两个运算数,相除后进栈st中(若除数为零,则提示相应的错误信息)。}
若字符串postexp扫描完毕,则数值栈op中的栈顶元素就是表达式的值。

解题思路

       将算术表达式转换为后缀表达式的主要思路为:在从左到右扫描算术表达式exp的一个运算符op时,如果栈为空或者栈顶为’(‘,直接将其进栈;如果栈不空,只有当op的优先级高于栈顶运算符的优先级时才直接将op进栈;否则依次出栈运算符并存人后缀表达式postexp。直到栈顶运算符的优先级小于op的优先级为止,然后再将op进栈。另外,在扫描exp遇到一个运算符op时,如果op为’(‘,表示一个子表达式的开始,直接将其进栈;如果op为’)’,表示一个子表达式的结束,需要出栈运算符并存人postexp,直到栈顶为’(‘,再将’(‘出栈。

       后缀表达式求值主要思路:从左到右扫描后缀表达式postexp,若读取的是一个操作数,将它进操作数栈。若读取的是一个运算符op,则从操作数栈中连续出栈两个操作数a和b,计算b op a的值,并将计算结果进操作数栈。当整个后级表达式扫描结束时,操作数栈中的栈顶元素就是表达式的计算结果。

代码实现

#include<iostream>
using namespace std;

#define MAXSIZE 50

//运算符栈类型定义
typedef struct
{
	char data[MAXSIZE];
	int top;
}StackOptr;

//操作数栈类型定义
typedef struct
{
	double data[MAXSIZE];
	int top;
}StackOpnd;

//初始化运算符栈
void InitStackOptr(StackOptr*& s)
{
	s = new StackOptr;
	s->top = -1;
}

//初始化操作数栈
void InitStackOpnd(StackOpnd*& s)
{
	s = new StackOpnd;
	s->top = -1;
}

//判断栈是否为空
template<typename T1>
bool StackEmpty(T1& s)
{
	if (s->top == -1)
		return true;
	return false;
}

//销毁栈
template<typename T1>
void DestroyStack(T1& s)
{
	delete s;
}

//进栈
template<typename T1, typename T2 >
bool Push(T1& s, T2 e)
{
	if (s->top == MAXSIZE - 1)
		return false;
	s->top++;
	s->data[s->top] = e;
	return true;
}

//出栈
template<typename T1, typename T2 >
bool Pop(T1& s, T2& e)
{
	if (s->top == -1)
		return false;
	e = s->data[s->top];
	s->top--;
	return true;
}

//取栈顶元素
template<typename T1, typename T2 >
bool GetTop(T1& s, T2& e)
{
	if (s->top == -1)
		return false;
	e = s->data[s->top];
	return true;
}

// 将中缀表达式exp转换成后缀表达式postexp
void trans(char* exp, char postexp[])
{

	char e;											// 给Pop与GetTop函数使用
	StackOptr* Optr;								//定义运算符栈指针
	int i = 0;										// i作为postexp 下标
	InitStackOptr(Optr);							//初始化运算符栈
	while (*exp != '\0')							//exp表达式未扫描时循环
	{
		switch (*exp)
		{
		case '(':									//判定为左括号
			Push(Optr, '(');
			exp++;									//exp指针前移,继续处理下一个字符
			break;
		case ')':									//判定为右括号
			Pop(Optr, e);							//一直出栈,直到遇到')'为止
			while (e != '(')
			{
				postexp[i++] = e;
				Pop(Optr, e);
			}
			exp++;
			break;
		case '+':									// 判定为'+'或'-'号
		case '-':
			while (!StackEmpty(Optr))               //直到栈空或者栈顶为'(',然后将其入栈
			{
				GetTop(Optr, e);
				if (e == '(')
					break;
				else
				{
					postexp[i++] = e;
					Pop(Optr, e);
				}
			}
			Push(Optr, *exp);						 //最后将 '+' 或'- '入栈
			exp++;
			break;
		case '*':									 //判定为'*'或'/'号
		case '/':
			while (!StackEmpty(Optr))				 //直到栈空或者栈顶为'(','*' 或'/ ',然后将其入栈
			{
				GetTop(Optr, e);
				if (e == '/' || e == '*')
				{
					postexp[i++] = e;
					Pop(Optr, e);
				}
				else
					break;
			}
			Push(Optr, *exp);						//最后将 '*' 或'/ '入栈
			exp++;
			break;
		default:									//处理数字字符
			while (*exp >= '0' && *exp <= '9')	    //循环判断处理多位数字
			{
				postexp[i++] = *exp;
				exp++;
			}
			postexp[i++] = '#';                      //以#标识一个数字串结束
		}
	}
	while (!StackEmpty(Optr))                         //此时exp扫描完毕,栈不空时循环
	{												  //将Optr中的的所有运算符依次出栈并存放到postexp
		Pop(Optr, e);
		postexp[i++] = e;
	}
	postexp[i] = '\0';								 //给postexp表达式添加结束标志
	DestroyStack(Optr);								//销毁栈
}

//计算后缀表达式的值
double compvalue(char* postexp)
{
	StackOpnd* Opnd;						//定义操作数栈
	InitStackOpnd(Opnd);					//初始化操作数栈
	double result;							//结果
	double a, b;							//弹出栈的两个数
	double c;								//计算弹出栈的两个数的算术运算结果
	double d;							    //将连续的数字字符转换成十进制整数保存在d里
	while (*postexp != '\0')				//postexp字符串未扫描完时循环
	{
		switch (*postexp)
		{
		case '+':                            //判定为'+'号 
			Pop(Opnd, a);                    //从Opnd栈中出栈两个数值a和b,c=a+b,将c入栈
			Pop(Opnd, b);
			c = b + a;
			Push(Opnd, c);
			break;
		case '-':							//判定为'-'号 
			Pop(Opnd, a);					//从Opnd栈中出栈两个数值a和b,c=b-a,将c入栈
			Pop(Opnd, b);
			c = b - a;						//注意是b-a,因为b后出栈
			Push(Opnd, c);
			break;
		case '*':							//判定为'*'号 
			Pop(Opnd, a);					//从Opnd栈中出栈两个数值a和b,c=b*a,将c入栈
			Pop(Opnd, b);
			c = b * a;
			Push(Opnd, c);
			break;
		case '/':							//判定为'/'号 
			Pop(Opnd, a);					//从Opnd栈中出栈两个数值a和b,若a!=0,则c=b/a,将c入栈
			Pop(Opnd, b);
			if (a != 0)                       //检查除数的合法性,若不合法,则退出程序
			{
				c = b / a;
				Push(Opnd, c);
				break;
			}
			else
			{
				cout << "\n除零错误!" << endl;
				exit(0);
			}

		default:									//处理数字字符
			d = 0;									//将连续的数字字符转换为对应数值存放到d中
			while (*postexp >= '0' && *postexp <= '9')
			{
				d = 10 * d + *postexp - '0';
				postexp++;
			}
			Push(Opnd, d);
		}
		postexp++;							//继续处理下一个字符
	}
	GetTop(Opnd, result);					//取栈顶元素,即运算最终结果
	delete Opnd;							//销毁栈
	return result;							//返回结果
}

int main()
{
	char exp[MAXSIZE];					//前缀表达式
	char postexp[MAXSIZE];				//后缀表达式
	cout << "请输入合法的中缀表达式:";
	cin >> exp;
	trans(exp, postexp);
	cout << "后缀表达式:" << postexp << endl        //输出后缀表达式和表达式结果
		<< "表达式结果:" << compvalue(postexp) << endl;
}

运行结果

 

 如有同校学弟学妹们见到这篇博客,切忌不要随意CV,请自主多动手多思考。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不开心就喝水

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值