数据结构算术表达式求值课程设计Word下载.docx

上传人:b****7 文档编号:22172455 上传时间:2023-02-02 格式:DOCX 页数:35 大小:208.72KB
下载 相关 举报
数据结构算术表达式求值课程设计Word下载.docx_第1页
第1页 / 共35页
数据结构算术表达式求值课程设计Word下载.docx_第2页
第2页 / 共35页
数据结构算术表达式求值课程设计Word下载.docx_第3页
第3页 / 共35页
数据结构算术表达式求值课程设计Word下载.docx_第4页
第4页 / 共35页
数据结构算术表达式求值课程设计Word下载.docx_第5页
第5页 / 共35页
点击查看更多>>
下载资源
资源描述

数据结构算术表达式求值课程设计Word下载.docx

《数据结构算术表达式求值课程设计Word下载.docx》由会员分享,可在线阅读,更多相关《数据结构算术表达式求值课程设计Word下载.docx(35页珍藏版)》请在冰豆网上搜索。

数据结构算术表达式求值课程设计Word下载.docx

D={ai|ai∈ElemSet,i=1,2,3……,n,n≥0}

数据关系:

R1={<

ai-1,ai>

|ai-1,ai∈D,i=1,2,3,……,n}

约定其中ai端为栈底,an端为栈顶。

操作集合:

见如下相关功能函数

}ADTSqStack

3.1.2相关功能函数

运算符栈的功能函数

OPTR栈

voidOptr_InitStack(Optr_Stack&

S1)

运算符栈的初始化

voidOptr_Push(Optr_Stack&

S1,chare)

运算符栈的栈顶插入新的数据元素

charOptr_Pop(Optr_Stack&

运算符的栈顶元素出栈

charOptr_GetTop(Optr_Stack&

取出运算符栈的栈顶元素

voidOptr_DispStack(Optr_Stack&

从栈底到栈顶依次输出各运算符

运算数栈的功能函数

OPND栈

voidOpnd_InitStack(Opnd_Stack&

S2)

运算数栈的初始化

intGetTop2(SqStack2&

获取运算数栈的栈顶元素

运算数栈的栈顶插入新的数据元素

floatOpnd_Pop(Opnd_Stack&

运算数栈的栈顶元素出栈

voidOpnd_DispStack(Opnd_Stack&

从栈底到栈顶依次输出各运算数

算术表达式的相关功能函数

charPrecede(charm,charn)

运算符的优先级比较函数

floatCalculate(floata,charrheta,floatb)

运算函数

voidEvaluate(Optr_Stack&

S1,Opnd_Stack&

判断算术表达式各字符如何入栈函数

3.1.3函数模块调用关系

3.2详细设计和编码

首先本程序定义两个顺序栈:

运算符栈(OPTR)和运算数栈(OPND);

OPTR栈定义如下:

typedefstruct{

char*base;

//算符栈的栈底

char*top;

//算符栈的栈顶

intstacksize;

//算符栈的最大长度

}Optr_Stack;

OPND栈定义如下:

float*base;

//操作数栈的栈底

float*top;

//操作数栈的栈顶

//操作数栈的最大长度

}Opnd_Stack;

然后是主要功能函数的详细设计:

(1)charPrecede(charm,charn)判断运算符优先权,返回优先权高的

算符间的优先关系如下:

θ1

θ2

+

-

*

/

#

>

<

=

函数实现如下:

charPrecede(charm,charn)//运算符的优先级比较

{

if(n=='

+'

||n=='

-'

)//输入符号为"

+"

、"

-"

{

if(m=='

('

||m=='

#'

)return'

'

;

//栈顶元素为"

("

#"

此时栈顶符号优先级低,返回"

"

elsereturn'

//否则,栈顶符号优先级高,返回"

}

elseif(n=='

*'

/'

)//输入的符号为"

*"

/"

{

)'

)"

此时栈顶符号优先级高,返回"

//否则,栈顶符号优先级低,返回"

)return'

//输入的符号为"

则直接返回"

='

此时优先级同,返回"

="

else//输入符号为其他

}

(2)voidEvaluate(Optr_Stack&

S2)以字符串形式输入算数表达式,根据是运算符还是运算数来判断如何入栈

函数实现如下:

charc;

floatt,e;

intn=0,i=1,j=0,k=0,l=0;

charch[STACK_INIT_SIZE];

ints=1;

intflag=0,flag2=0;

floatp1,p2;

charch1;

Optr_Push(S1,'

);

//将'

入栈,作为低级运算符

cout<

请输入不含变量的表达式(以#结束!

):

\n"

cin>

ch;

c=ch[0];

\n对表达式求值的操作过程如下:

<

\n********************************************************************************\n"

步骤\t运算符栈S1\t运算数栈S2\t字符表达式\t\t栈操作过程"

while(c!

||Optr_GetTop(S1)!

cout<

i++<

\t"

Optr_DispStack(S1);

cout<

\t\t"

Opnd_DispStack(S2);

if(flag==1)

{

k--;

flag=0;

}

if(flag2)

k+=flag2;

flag2=0;

for(l=0;

l<

k;

l++)

cout<

'

for(j=k;

ch[j]!

\0'

j++)

ch[j];

if(ch[k]!

&

flag!

=1){k++;

flag=0;

as:

if(!

(c=='

||c=='

))

{//输入的字符如果不是运算符号,则继续输入直到输入的是运算符为止,将非运算符转换成浮点数

if(!

.'

)&

n>

=0)//小数点前面的数

{

e=float(c-48);

n++;

if(n==1)t=e;

elseif(n>

1)t=t*10+e;

//转换小数点前面的部分

c=ch[s++];

}

if(n==-1)//小数点后面的数

//转换小数点后面的部分

t=t+e/10;

//最终将转换后的两部分加起来,转换成浮点数

if(c=='

n=-1;

if((c>

0'

c<

9'

)||c=='

flag2++;

gotoas;

if(c<

||c>

Opnd_Push(S2,t);

}

\t\tOpnd_Push(S2,"

t<

else//输入的是运算符

n=0;

//非运算型数据计数器清零

switch(Precede(Optr_GetTop(S1),c))//比较运算符的优先级

case'

:

//栈顶元素优先级低,则入栈且继续输入

Optr_Push(S1,c);

cout<

\t\tOptr_Push(S1,"

break;

//栈顶元素优先级相等,脱括号并接收下一字符

Optr_Pop(S1);

\t\tOptr_Pop(S1)"

//栈顶元素优先级高,则退栈并将运算结果入栈

p1=Opnd_Pop(S2);

p2=Opnd_Pop(S2);

ch1=Optr_Pop(S1);

Opnd_Push(S2,Calculate(p2,ch1,p1));

\t\tCalculate("

p2<

'

ch1<

p1<

flag=1;

i<

\t'

Opnd_GetTop(S2)<

for(j=0;

j<

j++)cout<

RETURN(GETTOP(S2))"

if(S2.top-1==S2.base)//显示表达式最终结果

\n表达式的结果为:

endl;

elsecout<

\n表达式出错!

\n"

(3)floatCalculate(floata,chartheta,floatb)

运算函数,运用else-if语句,不同的运算符则进行不同的运算;

进行除法时,若分母为0,则将标志标记成错误。

floatCalculate(floata,chartheta,floatb)//运算函数

floattmp=0;

if(theta=='

)tmp=a+b;

//从运算符栈取出的符号为"

,则运算数栈的两元素相加,并返回

elseif(theta=='

)tmp=a-b;

,则运算数栈的两元素相减,并返回

)tmp=a*b;

,则运算数栈的两元素相乘,并返回

)//从运算符栈取出的符号为"

,则运算数栈的两元素相除,并返回

if(b==0)cout<

除数不能为0!

elsetmp=a/b;

returntmp;

注:

其它函数详细设计及编码详见附录1

4.运行与测试

4.1上机调试

(1).语法问题及解决

由于本程序牵扯到四个方面的内容,首先是OPTR栈的相关功能函数的设计;

其次是OPND栈的相关功能函数的设计;

再次是算术表达式的具体计算涉及到的相关功能函数的设计,最后是主函数的设计;

前两个方面均为对顺序栈的基本操作,具有通用性,基本无语法错误;

主要是在设计算术表达式的具体计算的函数时,调用相关栈的函数以及其它语句时,出现了语法编辑的错误,还有在设计主函数的时候,由于要考虑到用户的使用方便,也出现了一些编辑语法错误,在反复使用加注释和单步运行两种方法对于具体错误分析、调试后,所有语法错误均得到解决。

(2)逻辑问题及解决

程序初步完成以后,进行测试发现出现死循环,观察显示结果发现,栈中的数据和运算符一直都没有出栈。

既然没有出栈,那么根据以前程序调试的经验,该问题应该出在栈的出栈操作中,于是找到进行出栈操作的函数,经仔细检查发现,原来将return语句写到了top—语句的前面去了,而return语句有跳出的作用,当它一旦执行,其后的语句都会被忽略而得不到执行。

因此将它们调换顺序,正确写法见源程序。

再次调试程序,输入一个测试表达式(如1+2*5#),发现结果是10,而且通过将栈中的数据进行显示发现1并未出栈,而操作符栈的“+”未进行运算便出了栈。

通过步步跟踪来走程序发现,原来错误出在优先级判断的条件语句里面,在取出栈顶元素与刚读入的运算符进行比较时,当刚读入的运算符优先级高于栈顶的运算符时,直接将刚读入的运算符入栈,而刚从栈顶取出的一个运算符却抛之不管,当然会出错,因此应将刚取出的先入栈,然后将刚读入的运算符入栈。

经过以上的修改,用一些简单的表达式进行测试发现能得出正确结果,但当输入像-7+1#或-(1+2*3)#这样的开头带负号的表达式时,程序计算的结果与实际相差甚远。

因此应将开始的“-”作为负号而不是减号,并进行特殊的处理。

当输入的计算数据超过9时(如12+56#),计算结果又出错,通过输出栈中的数据进行观察发现栈将12分成了1和2,将56分成了5和6进行分别存储。

这显然是错误的。

通过检查程序发现输入语句用的是c=getchar(),该输入语句每次只能得到一个字符,12是两个字符1和2,因此会出现上面的情况。

于是将输入改为字符串输入并存入一个字符数组中,然后将字符串转换成相应的运算符和数据以参与计算。

通过上面的更改,运行程序发现已经能接受大于9的数据以参与运算了;

但当输入一些特殊非运算用符和字母时,又出现了意想不到的错误结果,因此程序采用了相应的算法,在使用刚输入的表达式字符串前,进行严格的检测。

4.2算法时间和空间性能分析

时间上,对于含n个字符的表达式,无论是对其进行合法性检测还是对其进行入栈出栈操作n次,因此其时间复杂度为O(n)。

空间上,由于在本程序中,在为算符栈(OPTR)和操作数栈(OPND)涉及到两种情况时申请空间,一方面分别为OPTR栈和OPND栈申请了初始的存储单元,均为STACK_INITSIZE=100个;

另一方面,考虑到两个栈在处理具体的算术表达式时,有可能会出现溢出的情况,即栈的初始的存储空间不够用,这时需要为其申请额外的存储空间,每溢出一次,就为其申请存储单元STACKINCREMENT=10个;

所以,本程序的算法的空间复杂度一方面取决于算术表达式的长度,另一方面取决于本程序的所有代码所占用的存储空间大小。

4.3程序运行测试结果

计算表达式1024/(4*8)

输入用户选择“1”继续计算表达式3*(7-2)

输入用户选择“0”,退出程序

用“9/0”验证在除法中除数不能为0

结果分析:

以上调试结果是正确的。

能够实现各个符号优先级先后顺序的运算,根据符号优先级(、)、+、-、*、/,如此顺序进行运算,实现了基本表达式运算的功能。

a.可以完成四则混合运算

b.可以检查表达式的输入是否正确

c.演示表达式的求值的操作过程

5.总结与心得

5.1设计中难点的总结以及其它解决方案

难点一:

如何实现“算符优先关系”的比较

本报告方案:

利用if-else语句实现运算符优先级的比较。

其它方案:

行和列都按照'

、'

的顺序,将优先关系表存储在一个二维数组P中。

判别两个运算符的优先关系就转化为查找相应的二维数组的元素值的过程:

charPrecede(charc1,charc2)

{//根据操作符c1和c2的序号确定其优先关系P[i][j]。

inti,j;

charP[7][7]={{'

},{'

},

{'

$'

$'

}};

i=LocateChar(c1);

//定位c1在'

('

中的位

序,从0开始计数

j=LocateChar(c2);

//定位c2在'

if(P[i][j]=='

){cout<

”算符不匹配!

“;

break;

returnP[i][j];

‚难点二:

如何设定栈中元素的类型

设立两套栈的定义和操作,即分别定义数据元素为char型和数据元素为float型的两个栈,并且设定两种不同类型数据的栈的Push、Pop等操作。

这样做的好处在于,将数字的运算范围扩大到float,不同类型的元素存储的时候“各得其所”,互不影响,缺点在于程序会写得重复而冗长。

其它方案:

只定义一种栈的类型,即把栈中的元素统一定义为float型,只需在实现Calculate函数的时候,对“theta”进行强制类型转换即可,虽然表面上会造成精度缺失,但theta本身是一个字符,也算是整型,故对于运算结果不会有影响。

SElemTypeCalculate(SElemTypea,SElemTypetheta,SElemTypeb)

{//Calculate为进行二元运算的athetab的函数

charn=char(theta);

//此处把double型强制转换成char型

switch(n)//转换后相当于和符号匹配ACSII码

{case'

returna+b;

case'

returna-b;

returna*b;

returna/b;

难点三:

如何将连续的数字字符及小数点转换为实型数字

本报告方案:

分别转换小数点之前的部分和小数点之后的部分,再把两部分求和。

其它方案:

定义一个字符数组Data[i],用来存储数字字符及小数点构成的子串,利用函数atof,可以很容易地将其转换为相应的实型数字:

floatChartoFloat2()

{inti=0;

floatd;

c=getchar();

while(c>

Data[i]=c;

i++;

Data[i]='

//数字没有存满,输入字符串结束符

d=ato

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 经管营销 > 销售营销

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1