基于栈结构的浮点型数据表达式求值算法

0  引言

表达式求值是程序设计语言编译中的一个基本问题,对于按常规输入即中缀表达式输入格式的表达式

求值问题是程序设计语言编译中的一个重要问题,涉及到了整型数据的运算和浮点型数据的运算。下面通

过编译程序设计中的词法分析原理和数据结构的知识,在“算符优先法”的基础上,介绍一种简单、有效的表

达式求值的扩充算法,该算法在整型数据算法的基础上扩充到了浮点型数据的运算。

1  表达式的文法

为了叙述的方便,把讨论局限在算术表达式中,并且在不影响实质的前提下,把研究的表达式进行简化,

下列文法给出了要讨论的表达式:

基本符号集:{0 ,1···,9 , + , - , 3 ,/ , ( ,) ,·,&} ;

语法成分集:{ < 表达式> , < 常数> , < 运算符> , < 数字> } ;

语法公式集包括以下产生式:

< 表达式>nn = < 常数> | < 表达式> < 运算符> < 表达式> | < 表达式>

< 常数>nn = < 数字> | < 数字> < 常数> | < 常数> < ·> < 常数>

< 数字>nn = 0| 1| ···| 9

< 运算符>nn = + | - | 3 | /

用上述文法定义的表达式与普通的表达式一样,把运算符放在两个运算对象中间,所以又称中缀表达

式。中缀表达式的计算必须按照如下规则进行:

(1) 先执行括号内的运算,再执行括号外的运算。在具有多层括号时,按层次反复使用本条规则;

(2) 在无括号或同层括号内的计算是首先计算乘( 3 ) 和除(/ ) ,然后计算加( + ) 和减( - ) ;

(3) 在有多个3 / (+ - ) 运算可以选择时,按从左到右的顺序执行;

2  中缀表达式求值算法

为了说明算法,把运算符的集合命名为OP ,把左右括号和表达式结束符统称为界限符,并把运算符和界

限符统称为算符。根据表达式文法,在运算的每一步中,任意两个相继出现的算符θ1 和θ2 之间的优先关系

至多是下面三种关系之一:

θ1 <θ2  θ1 的优先权低于θ2

θ1 =θ2  θ1 的优先权等于θ2

θ1 >θ2  θ1 的优先权高于θ2

1 定义了算符之间的这种优先关系

由表达式文法可知, + , - , 3 ,/ 的优先性均低于‘(’但高于‘) ,当优先性相等时,根据表达式从左至右

的运算规则,令前者的优先权大于后者。为了算法简洁,在表达式的最左边也虚设一个‘ # ’构成整个表达式

的一对括号。表中的‘(=) ’表示当左右括号相遇时,括号内的运算已经完成。同理‘, # = # ’表示整个

表达式求值完毕。

为实现该算法,可以使用两个工作栈,一个称做OPTR ,用于寄存运算符;另一个称做OPND ,用于寄存操

作数或运算结果。算法的基本思想是:

1  算符间的优先关系

θ2      θ1

+

-

*

/

(

)

#

+

>

-

*

/

(

=

 

)

 

#

 

=

 

1) 首先置操作数栈为空栈,表达式起始符“ # ”为运算符栈的栈底元素;

2) 依次读入表达式中每个字符,若是操作数则进OPND ,若是运算符,则和OPTR 栈底栈顶运算符比较

优先权后做相应操作,直至整个表达式求值完毕(OPTR 栈的栈顶元素和当前读入的字符均为“ # )

算法1 中缀表达式求值算法(c 描述)

1. 1  置初态

InitStack (OPTR) ; InitStack (OPND) ; Push (OPTR ,# ) ; c = getchar () ;

初始化操作数栈与运算符栈,并将表达式起始符号“ # ”置入栈底。

同时,开始读取表达式。

1. 2  当读入的符号c 不是“ # ,或者运算符栈顶元素不是“ # ,则反复执行下列语句:

1. 2. 1) 判断c 是操作数还是运算符

if ( ! In (c ,op) 执行Push (OPND ,c) ; c = getchar () ;

否则,执行1. 2. 2) 操作;

1. 2. 2) 该操作为确定了c 为运算符以后的操作,因而将c 与运算符栈栈顶运算符相比较,根据比较结果

分几种情况执行:

1. 2. 2. 1) case < : 执行push (OPTR ,c) ; c = getchar () ;

1. 2. 2. 2) case = : 执行pop (OPTR ,x) ; c = getchar () ;

1. 2. 2. 3) case > : 执行pop (OPTR ,theta) ; pop (OPND ,b) ; pop (OPND ,a) ; push (OPND ,operate (a ,theta ,

b) ) ;

1. 3  跳出循环后,则执行return (gettop (OPND) ) ;

1. 4 程序结束。

3  浮点型数据表达式的求值算法

分析以上算法,不难发现,该算法只支持0 - 9 的整型数字的运算,对于超过9 的整型和浮点型数据显然

程序报错,因而为了实现浮点型数据的运算,在以上算法的基础上添加了两个关键步骤,就是浮点数据的读

入与组合,具体思路如算法2

算法2 浮点型数据表达式求值算法(只列出以上算法基础上增加的关键步骤)

2. 1  置初态:z[ ] = # ;

2. 2  程序运行到以上算法的1. 2. 1) ,(c > = 0) &&(c < = 9) | | (c = = . ) 执行浮点型数据的读入操

:i = 0 ;并循环执行下列操作:

z[ i ] = c ;i + + ;scanf (%c,&c) ;

2. 3  若循环退出,则执行浮点型数据的组合操作:

2. 3. 1) i = 0 ; sum = 0 ; n = 0 ; k = 1 ; j = 10 ; z[ i ] ! = # ’则循环执行下列操作

2. 3. 1. 1) z[ i ] = = . ’执行:

j = 1 ;n = 1 ;

否则,执行:2. 3. 1. 1. 1) n = = 1 执行k = k 3 0. 1 ;

2. 3. 1. 1. 2) sum = sum 3 j + ( (float) (z[ i ] - 0) ) 3 k ;

2. 3. 1. 2) z[ i ] = # ;i + + ;

2. 3. 2) 若循环退出,sum 已经存储了输入的浮点型数据,则执行:

push (OPND ,sum) ;

以上算法可以用Pacal C/ C + + 语言实现,当用户输入中缀表达式时,数字前面要是再带一个正、负符

号的话,则按照+ = (0 + 1) 3 - = (0 - 1) 3 的规则替换。

例如:当输入如下中缀表达式时

(0 - 1) 3 1. 3 + 5 - (3. 2 + 2 3 3) 3 2. 1 # 则程序输出结果为- 15. 62

4  基于栈结构浮点型数据表达式求值算法在教学中的实际意义

栈实际上是一种特殊的线性结构,在实际应用和教学中之所以称之为栈结构,是由于基于栈结构的算法

和操作均是遵循“先进后出”的规则,而有些算法思想就是要利用这样的规则才更方便地实现和应用,浮点型

表达式求值就是其中之一。教学中该算法的展现,不仅让学生在线性结构方面会有更深一步的了解和掌握,

而且更能激发他们对基于栈结构或者说是线性结构的算法创新、结构创新。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值