使用堆栈实现对算数四则混合运算表达式的求值(C语言)

本文介绍了如何使用堆栈实现对包含加、减、乘、除的算数四则混合运算表达式进行求值,主要涉及问题分析、算法描述、代码实现和一些说明。通过设置运算符堆栈和运算数堆栈,根据运算符优先级进行计算。文章提供了源代码示例和测试数据,并提到了处理括号、错误情况及扩展运算功能的方法。
摘要由CSDN通过智能技术生成

使用堆栈实现对算数四则混合运算表达式的求值(C语言)



一、问题分析

基本思路

想要用算法来计算一个算术表达式(字符串),要能够正确地解释表达式。首先,明确一下四则运算的基本规则:

  • 先乘除,后加减
  • 从左到右计算
  • 先括号内,后括号外

可以在一边入栈的过程中,一边根据运算规则一步步计算式子。问题在于堆栈如何设置。假设是一个简单的不含括号的四则运算,尝试只使用一个堆栈来解决问题。举个例子:

e.g. 3+4*5-1#(#作为结束符)
1、首先3入栈,+入栈,下一个字符是4,这个时候就遇到一个问题,在不知道下一个字符是乘除还是加减的情况下,不能进行3+4的计算。
2、于是4也入栈,读取下一个字符,发现是 *,于是 * 入栈
3、读取下一个字符5,同时读取栈顶发现是 * ,可以计算,于是 * 出栈,4出栈,4 * 5 得到20并暂存。
4、读取栈顶字符发现是 + ,读取下一个字符,发现是 - ,所以要进行3+20的计算
5、类似,后续计算过程省略

观察上述计算过程,我们发现在判断是否执行一步计算的时候,首先要做的是判断相邻两个运算符的优先级,然后才能决定是否进行计算。这给我们一种启发,设置两个堆栈,运算符堆栈(OPRT)与运算数堆栈(OPND),分别存储运算符(Operator)与运算数(Operand),将使进出栈的步骤简化,判断算符优先级的过程更为容易。

算符优先级构建

我们用> 、=、<来简单表示左算符sym1与右算符sym2对比下的优先级。sym1存在算符栈栈顶,而sym2为刚从字符串中读取到的字符。

  1. sym1>sym2 执行sym1的计算,sym1出栈
  2. sym1<sym2 sym2进栈
  3. sym1=sym2 左右括号相遇,表示括号内计算完成,sym1出栈,sym2清空

列表如下:

sym1\sym2 + - * / ( ) #
+ > > < < < > >
- > > < < < > >
* > > > > < > >
/ > > > > < > >
( < < < < < = EORROR
) > > > > ERROR > >
# < < < < < ERROR =

1、乘除优先级大于加减,同级运算符处于左侧时优先级更大
2、sym1=‘(’ 时,要进行该括号右侧的运算,sym2应当入栈所以sym1<sym2
3、sym2=’(’ 时,要进行该括号右侧的运算,此时sym2应当入栈所以sym1<sym2
4、sym2=’)’ 时,要进行该括号左侧的运算,并使sym1出栈,所以sym1>sym2
5、sym1=‘(’ 且sym2=’)‘时表示括号内运算完成,消去一对括号,所以sym1=sym2
6、一般来说,‘)’ 在括号内计算结束后就被消去了,没有入栈的情况,因此若 ‘)’ 在栈内,应当进行消括号的操作,将消括号的操作定义为 “ ’)’ 的运算”
7、‘#’ ‘#’表示表达式计算完成(在栈底放置’#‘ 用来与结束符对应)
8、几种表达式错误的情况:’)’ num ‘(’ ,’#’ num ‘)’,’(’ num ‘#’ ,在表达式括号不匹配时会出现以上情况,应当报错

二、算法描述

  • 设置两个工作栈,OPTR寄存运算符,OPND寄存运算数或者中间运算结果
  • 首先置操作数栈为空栈,起始符 ’#‘ 作为栈底元素
  • 依次读入表达式字符,运算数进OPND栈,运算符和栈顶元素进行优先级比较后再进行相应操作。
  • OPTR中栈顶元素与当前读入字符均为’#‘时求值结束,结果输出

算法描述

OperandType EvaluateExpression(){
   
//OP为运算符合集
InitStack(OPTR); Push(OPTR,'#');
InitStack(OPND); c=getchar();
while(c!=#||GetTop(OPTR)!='#'){
   
	if(!In(c,OP)){
   Push(OPND,c); c=getchar(); }  //不是运算符则进栈
	else
		switch(Precede(GetTop(OPTR),c)){
   
			case'<':	//符号入栈
				Push(OPTR,c); c=getchar();
				break;
			case'=':	//脱括号并接收下一个字符
				Pop(OPTR,x); c=getchar();
				break;
			case'>':	//退栈并将运算结果入栈
				Pop(OPTR,theta);
				Pop(OPND,b); Pop(OPND,a);
				Push(OPND,Operate(a,theta,b));
				break;
			} //switch
		} //while
		return GetTop(OPND);	//返回运算结果
	} //EvaluateExpression

函数说明:

InitStack(S) //构造一个空栈
Push(S,e) //入栈
Pop(S,x) //出栈
GetTop(S) //返回栈顶元素
In(c,OP) //比较,判断c是否为OP中的运算符
Precede(c1,c2) //比较两个运算符c1与c2的优先级,并返回> = <
Operate(num1,sym,num2) //执行运算操作,num1、num2为运算数,sym为运算符

堆栈运算过程的直观体现

e.g.3*(7-2)

步骤 OPTR栈 OPND栈 输入字符 主要操作
1 # 3 ‾ \underline{3} 3 * \text{*} *(7-2) # Push(OPND,’ 3 \text{3} 3’)
2 # 3 ∗ ‾
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值