表达式求值实验报告.docx
《表达式求值实验报告.docx》由会员分享,可在线阅读,更多相关《表达式求值实验报告.docx(27页珍藏版)》请在冰豆网上搜索。
表达式求值实验报告
淮海工学院计算机工程学院
课程设计报告
设计名称:
数据结构课程设计
选题名称:
表达式求值
姓名:
学号:
专业班级:
系(院):
计算机工程学院
设计时间:
设计地点:
软件工程实验室、教室
成绩:
指导教师评语:
签名:
年月日
1.课程设计目的
1、训练学生灵活应用所学数据结构知识,独立完成问题分析,结合数据结构理论知识,编写程序求解指定问题。
2.初步掌握软件开发过程的问题分析、系统设计、程序编码、测试等基本方法和技能;
3.提高综合运用所学的理论知识和方法独立分析和解决问题的能力;
4.训练用系统的观点和软件开发一般规范进行软件开发,巩固、深化学生的理论知识,提高编程水平,并在此过程中培养他们严谨的科学态度和良好的工作作风。
2.课程设计任务与要求:
任务
根据教材《数据结构-C语言描述》(耿国华主编)和参考书《数据结构题集(C语言版)》(严蔚敏、吴伟民主编)选择课程设计题目,要求通过设计,在数据结构的逻辑特性和物理表示、数据结构的选择应用、算法的设计及其实现等方面加深对课程基本内容的理解和综合运用。
设计题目从任务书所列选题表中选取,每班每题不得超过2人。
学生自选课题
学生原则上可以结合个人爱好自选课题,要求课题有一定的深度与难度,有一定的算法复杂性,能够巩固数据结构课程所学的知识。
学生自选课题需在18周前报课程设计指导教师批准方可生效。
要求:
1、在处理每个题目时,要求从分析题目的需求入手,按设计抽象数据类型、构思算法、通过设计实现抽象数据类型、编制上机程序和上机调试等若干步骤完成题目,最终写出完整的分析报告。
前期准备工作完备与否直接影响到后序上机调试工作的效率。
在程序设计阶段应尽量利用已有的标准函数,加大代码的重用率。
2、.设计的题目要求达到一定工作量(300行以上代码),并具有一定的深度和难度。
3、程序设计语言推荐使用C/C++,程序书写规范,源程序需加必要的注释;
4、每位同学需提交可独立运行的程序;
5、每位同学需独立提交设计报告书(每人一份),要求编排格式统一、规范、内容充实,不少于10页(代码不算);
6、课程设计实践作为培养学生动手能力的一种手段,单独考核。
3.课程设计说明书
一需求分析
[问题描述]
一个算术表达式是由操作数(operand)、运算符(operator)和界限符(delimiter)组成的。
假设操作数是正整数,运算符只含加减乘除等四种运算符,界限符有左右括号和表达式起始、结束符“#”,如:
#(7+15)*(23-28/4)#。
引入表达式起始、结束符是为了方便。
编程利用“算符优先法”求算术表达式的值。
[基本要求]
(1)从键盘读入一个合法的算术表达式,输出正确的结果。
(2)显示输入序列和栈的变化过程。
二概要设计
1、设定“操作数”的栈的抽象数据类型定义:
ADTSqStack_f{
数据对象:
D={
数据关系:
R1={<
>|
i=2,…,n}
约定
端为栈顶,
端为栈底。
基本操作:
InitStack_f(&S)
操作结果:
构造一个空栈S。
GetTop_f(&S,&e)
初始条件:
栈S已存在。
操作结果:
用e返回S的栈顶元素。
Push_f(&S,ch)
初始条件:
栈S已存在。
操作结果:
插入元素ch为新的栈顶元素。
Pop_f(&S,&e)
初始条件:
栈S已存在。
操作结果:
删除S的栈顶元素,并以e返回其值。
}ADTSqStack_f
2、设定“操作符”的栈的抽象数据类型定义:
ADTSqStack_c{
数据对象:
D={
数据关系:
R1={<
>|
i=2,…,n}
约定
端为栈顶,
端为栈底。
基本操作:
InitStack_c(&S)
操作结果:
构造一个空栈S。
GetTop_c(&S,&e)
初始条件:
栈S已存在。
操作结果:
用e返回S的栈顶元素。
Push_c(&S,ch)
初始条件:
栈S已存在。
操作结果:
插入元素ch为新的栈顶元素。
Pop_c(&S,&e)
初始条件:
栈S已存在。
操作结果:
删除S的栈顶元素,并以e返回其值。
}ADTSqStack_c
3、本程序包含六个模块
1)主程序模块
voidmain()
{
初始化;
while(命令==“继续”)
{
接受数据;
处理数据;
接受命令;
}
}
2)栈模块——实现栈抽象数据类型
3)判断运算符优先级模块——判断运算符的优先级别
4)后缀表达式转换模块——将中缀表达式转换为后缀表达式,方便操作
5)无括号表示式求值运算模块——根据后缀表达式求值,并输出中间和最终结果
6)运算结果输出模块——以正确形式输出表达式的值
三详细设计
1、主程序中需要的全程量
#defineTTACK_INIT_SIZE100//初始分配最大空间量
#defineSTACKINCREMENT10//(默认)增补空间量
2、结点类型、指针类型
typedefstruct{
float*base;//存储实型数据元素的一位数组
float*top;//栈顶指针
intstacksize;//栈数组容量
}SqStack_f;//有序存储实型的顺序表类型
typedefstruct{
char*base;//存储字符数据元素的一位数组
char*top;//栈顶指针
intstacksize;//栈数组容量
}SqStack_c;//有序存储字符型的顺序表类型
voidInitStack_f(SqStack_f*s)
voidInitStack_f(SqStack_f*s)
//构造一个存储实型(字符型)的空栈,预设空间为100,分配失败就退出
voidGetTop_f(SqStack_f*s,float*e)
voidGetTop_c(SqStack_c*s,char*e)
//若栈s不空,则以e带值返栈顶元素,否则显示错误“ERROR”,并退出程序
voidPush_f(SqStack_f*s,floate)
voidPush_c(SqStack_c*s,chare)
//在s的栈顶插入新的栈顶元素e,若栈的当前空间已满,则追加存储空间
voidPop_f(SqStack_f*s,float*e)
voidPop_c(SqStack_c*s,char*e)
//若栈s不空,则删除栈s的栈顶元素,用e带值返回,否则退出程序
其中部分操作的伪码算法(由于比较类似,以浮点型的栈为例)
voidInitStack_f(SqStack_f*s)
{//构造一个存储实型的空栈,预设空间为100,分配失败就退出
s->base=(float*)malloc(TTACK_INIT_SIZE*sizeof(float));
if(!
s->base)
exit
(1);
s->top=s->base;
s->stacksize=TTACK_INIT_SIZE;
}
voidGetTop_f(SqStack_f*s,float*e)
{//若栈s不空,则以e带值返栈顶元素,否则显示错误“ERROR”,并退出程序
if(s->top==s->base)
{
printf("ERROR!
\n");
exit
(1);
}
*e=*(s->top-1);
}
voidPush_f(SqStack_f*s,floate)
{//在s的栈顶插入新的栈顶元素e,若栈的当前空间已满,则追加存储空间
if(s->top-s->base>=s->stacksize)
{
s->base=(float*)realloc(s->base,(s->stacksize+STACKINCREMENT)*sizeof(float));
if(!
s->base)
{
printf("OVERFLOW!
\n");
exit
(1);
}
s->top=s->base+s->stacksize;
s->stacksize+=STACKINCREMENT;
}
*s->top++=e;
}
voidPop_f(SqStack_f*s,float*e)
{//若栈s不空,则删除栈s的栈顶元素,用e带值返回,否则退出程序
if(s->top==s->base)
exit
(1);
*e=*--s->top;
}
3、判断运算符优先级的算法:
算符间的优先关系如下:
+
-
*
/
(
)
#
+
>=
<
<
<
<
>
>
-
>
>=
<
<
<
>
>
*
>
>
>=
>
<
>
>
/
>
>
>
>=
<
>
>
(
<
<
<
<
<
=
)
>
>
>
>
>
>
#
<
<
<
<
<
=
伪码算法:
intprecede(charTop_char,chars1_char)
{//栈顶的运算符赋给Top_char,新读入的运算符赋给s1_char。
判断它们的优先级
//若栈顶运算符优先级高,则返回1,否则返回0
inti,pre[2];
charop[2];
op[0]=Top_char;//栈顶的运算符赋给op[0]
op[1]=s1_char;//新读入的运算符赋给op[1]
for(i=0;i<2;i++)
switch(op[i])
{
case'(':
case')':
pre[i]=0;break;//将括号的优先级设为0
case'+':
case'-':
pre[i]=1;break;//将+-运算符的优先级设为1
case'*':
case'/':
pre[i]=2;break;//将*/运算符的优先级设为2
case'^':
pre[i]=3;break;//将^运算符的优先级设为3
}
if(pre[0]>=pre[1])//栈顶元素优先级高返回1
return1;
else
return0;//否则返回0
}
4、中缀表达式转换为后缀表达式的算法:
算法过程描述:
1)首先将左括号“(”压进栈,作为栈底元素;
2)从左而右对算数表达式进行扫描,每次读入一个字符s1[i];
3)若遇到数字或小数点,则立即写入s2[i],若遇算数运算符,将“”(空格)写入s2[i];
4)遇到左括号“(”则压栈;
5)若遇算术运算符,如果它们的优先级比栈顶元素高,则直接进栈,否则弹出栈顶元素输出到s2[i],直到新栈顶元素的优先级比它低,然后将它压栈;
6)若遇到右括号“)”,则将栈顶元素输出到s2[i],直到栈顶元素为“(”,然后相互抵消;
7)当扫描到“#”符号,表明表达式串已全部输入,将栈中的运算符全部输出到s2[i],并删除栈顶元素。
伪码算法:
voidTranslate(char*s1)
{//中缀表达式转换为后缀表达式
chars2[80];
SqStack_cOptr;
inti=0,j=0;
chart;
InitStack_c(&Optr);//初始化一个存储字符型的空栈,便于存储运算符
Push_c(&Optr,'(');//首先将左括号“(”压进栈,作为栈底元素
while(s1[i]!
='#')//当扫描到的不是“#”,即表达式串没结束时
{
if(s1[i]>='0'&&s1[i]<='9'||s1[i]=='.')//若果是数字或小数点则将其输出给s2[i]
{
s2[j++]=s1[i];
if((s1[i+1]<'0'||s1[i+1]>'9')&&s1[i+1]!
='.')
s2[j++]='';
}
else
switch(s1[i])//扫描到的是运算符
{
case'(':
Push_c(&Optr,s1[i]);break;//遇到左括号“(”则压栈
case')':
Pop_c(&Optr,&t);//若遇到右括号“)”,则将栈顶元素输出到s2[i]
while(t!
='(')//直到栈顶元素为“(”,然后相互抵消
{
s2[j++]=t;
Pop_c(&Optr,&t);
}
break;
default:
while(GetTop_c(&Optr,&t),precede(t,s1[i]))
{//遇到算数运算符则比较优先级
Pop_c(&Optr,&t);//栈顶元素优先级高,则弹出到s2[i]
s2[j++]=t;
}
Push_c(&Optr,s1[i]);//栈顶元素优先级低,直接压栈
}
i++;
}
Pop_c(&Optr,&t);
while(t!
='(')//表达式串已结束,栈中的运算符全部输出到s2[i],并删除栈顶元素
{
s2[j++]=t;
Pop_c(&Optr,&t);
}
for(i=0;is1[i]=s2[i];
s1[i]='#';
s1[i+1]='\0';//为了方便打印后缀表达式,在字符串结尾加‘\0’
}
5、表示式求值运算的算法:
算法描述:
1)读入无括号的后缀表达式;
2)若为数值和小数点则将其联合转换为浮点型后进栈(存放操作数);
3)若为运算符,让栈顶元素和次顶元素与次运算符进行相应的运算,运算结果打印并进栈;
4)重复2)3)步骤,直到输入为“#”,则此时栈中的结果便是所追求的表达式的值。
数值转换为实数的算法描述:
1)若为数字,则将其减去'0'的ASCII码后就得到该数的数值,并暂存于一个变量m上;
2)若继续为数字,也将其减去'0'的ASCII码后就得到该数的数值,并将其值加上已存的m*10后的值再存于m;
3)重复2)步骤直到遇到小数点,从小数点后的数开始,在重复2)步骤的通知,也记下小数点后的位数n;
4)当遇到“”(空格)后,即表示此轮需转换的数已读入完毕,则将m除以10的你次方,则此时的之记为转换后的实数。
伪码算法:
voidCalculate(SqStack_f*s,char*s2)
{
floatm,x,y,z;
inti=0,j=0;
while(s2[i]!
='#')//读入后缀表达式直到“#”符号为止
{
if(s2[i]>='0'&&s2[i]<='9'||s2[i]=='.')//若为数值和小数点
//则将其联合转换为浮点型后进栈
{//数值转换为实数
m=0;
while(s2[i]!
=''&&s2[i]!
='.')//读入的只为数字
m=m*10+(float)(s2[i++]-'0');//转换为十进制的整数
if(s2[i]=='.')//遇到小数点后
{
j=0;i++;
while(s2[i]!
='')
{
m=m*10+(float)(s2[i++]-'0');//转换为十进制的整数
j++;//记录小数点后的位数
}
while(j>0)//转换为实数
{
m/=10;
j--;
}
}
i++;
Push_f(s,m);
GetTop_f(s,&m);
printf("Theresultis:
%g\n",m);
}
else//读入的为运算符
{
Pop_f(s,&x);//弹出栈顶元素
Pop_f(s,&y);//弹出次顶元素
switch(s2[i])
{//让栈顶和次顶元素与次运算符进行相应的运算,运算结果打印并进栈
case'+':
z=y+x;printf("Theresultis:
%g\n",z);break;
case'-':
z=y-x;printf("Theresultis:
%g\n",z);break;
case'*':
z=y*x;printf("Theresultis:
%g\n",z);break;
case'/':
if(x==0)
{//报错功能
printf("表达式出错,除数为‘0’,无意义\n");
exit
(1);
}
else
{
z=y/x;
printf("Theresultis:
%g\n",z);break;
}
case'^':
z=1;for(j=1;j<=x;j++)
{//乘方的运算
z=z*y;
printf("Theresultis:
%g\n",z);
}
}
Push_f(s,z);
i++;
}
}
}
6、结果输出的伪码算法:
voidresult(SqStack_f*s)
{
floatv;
GetTop_f(s,&v);
printf("Thefinalresultis:
%g\n",v);//以合适的形式输出结果,省去不必要的小数点
}
7、主程序的伪码算法:
voidmain()
{
SqStack_fstack;
charstr[80],c='Y';
while(c=='y'||c=='Y')//判断是否继续本程序
{
printf("请输入算术表达式[本程序支持实数的加减乘除乘方运算],结束前请输入‘#’号!
\n");
gets(str);//输入表达式
InitStack_f(&stack);//初始化一个存储运算结果(实型)的栈
Translate(str);//调用“中缀表达式转换为后缀表达式函数”
printf("转化后的后缀表达式为:
\n");//检验后缀表达式是否转换正确
puts(str);//输出后缀表达式
Calculate(&stack,str);//计算无括号表达式的值
result(&stack);//调用“结果输出函数”
printf("你想继续吗?
'Y'或'y'为继续,其余为退出程序\n");//增加程序的连续输入功能
c=getchar();
getchar();//吞噬掉输入判断符后的‘\n’
}
}
四设计与调试分析
1、在编程过程中,为了增加程序的实用性,将程序适用范围扩大到了实数型,并增加了连续输入功能;
2、在编程过程中,为了增加程序的健壮性,在运算除法时,考虑到除数为“0”时的报错和及时退出;
3、在调试过程中,最初一下子出来程序就出错,为了方便检查错误,故在主函数中增加了检查后缀表达式是否转换正确的函数,并在每一步计算都跟踪结果是否正确;
4、从程序实验题的编制过程中容易看出,线性表的广泛应用,特别是顺序存储结构的栈的应用。
本题中涉及两元素类型(字符型和浮点型)的栈,由于是面向过程的语言,故只能分别定义。
五用户手册
1、本程序的运行环境为Windows7旗舰版操作系统,执行文件为:
算术表达式求值.exe;
2、进入程序后即显示提示信息:
“请输入算术表达式,以’#’结束”以等待用户输入待求表达式,直到输入“#”为止,若用户输入的表达式为一个空字符串,则显示ERROR,程序结束;
3、在用户正确输入表达式后,程序会自动将其转换为后缀表达式并输出“转化后的后缀表达式为:
xxxxxxxx”,然后自动计算表达式的值并输出中间结果“Theresultis:
xxxxx”和最终结果“Thefinalresultis:
xxxx”;
4、最终结果输出后,又有提示信息:
“你想继续吗?
'Y'或'y'为继续,其余为退出程序”,以等待用户输入是否继续运行本程序的命令符,若输入“y”或“Y”,则程序自动再次运行,重复2,3步,若输入其它,程序结束。
5、本程序只对实数的加减乘除乘方运算进行求值,且只对“()”这种形式的括号进行识别,“{}”或“[]”都不予以识别,表达式输入完后一定要加“#”表示输入结束。
六测试成果
1、程序主界面
2、输入正确的表达式
输入10*(4.8/4+3^2-5)#,会打印出该式的后缀表达式,并求出最终结果
当进行完一次运算后,输入Y或y会继续进行下一次运算
3、输入除数为0的表达式
输入10*(2.7/(3^2-9)-1)#后,会提示除数为0,无意义
4、输入错误的格式
输入15+a#后,会提示ERROR并退出程序
七附录(源程序清单)
#include
#include
#include
#defineTTACK_INIT_SIZE100//初始分配最大空间量
#defineSTACKINCREMENT10//(默认)增补空间量
typedefstruct{
float*base;//存储实型数据元素的一维数组
float*top;//栈顶指针
intstacksize;//栈数组容量
}SqStack_f;//有序存储实型的顺序表类型
typedefstruct{
char*base;//存储字符数据元素的一维数组
char*top;//栈顶指针
intstacksize;//栈数组容量
}SqStack_c;//有序存储字符型的顺序表类型
voidInitStack_f(SqStack_f*s)
{//构造一个存储实型的空栈,预设空间为100,分配失败就退出
s->base=(float*)malloc(TTACK_INIT_SIZE*sizeof(float));
if(!
s->base)
exit
(1);
s->top=s->base;
s->stacksize=TTACK_INIT_SIZE;
}
voidInitStack_c(SqStack_c*s)
{//构造一个存储字符型的空栈,预设空间为100,分配失败就退出
s->base=(char*)malloc(TTACK_INIT_SIZE*sizeof(char));
if(!
s->base)
exit
(1);
s->top=s->base;
s->stacksize=TTACK_INIT_SIZE;
}
voidGetTop_f