数据结构课程设计1.docx
《数据结构课程设计1.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计1.docx(18页珍藏版)》请在冰豆网上搜索。
![数据结构课程设计1.docx](https://file1.bdocx.com/fileroot1/2022-12/31/47cc7525-b071-4bac-8a66-2f0cea0a3c67/47cc7525-b071-4bac-8a66-2f0cea0a3c671.gif)
数据结构课程设计1
软件学院
课程设计报告书
课程名称数据结构
设计题目算术表达式求值演示
专业班级软件工程09-05
学号0920010504
姓名韩亮
指导教师孙宁
2010年12月31日
目录
1.设计时间……………………………………………………………3
2.设计目的……………………………………………………………3
3.设计任务……………………………………………………………3
4.设计内容……………………………………………………………3
4.1需求分析……………………………………………………………3.
4.1.1程序所要实现的功能……………………………………………3
4.1.2输入形式和输入值的范围………………………………………3
4.1.3输出形式…………………………………………………………3
4.1.4测试数据…………………………………………………………3
4.2总体设计……………………………………………………………3
4.2.1设定栈的抽象数据类型定义:
…………………………………3
4.2.2程序流程图:
……………………………………………………4
4.2.3模块调用关系:
…………………………………………………5
4.3详细设计:
………………………………………………………5
4.3.1数据类型的实现…………………………………………………5
4.3.2主程序和其他主要函数的伪码:
…………………………………6
4.3.3各函数之间的调用关系:
………………………………………10
4.4测试与分析…………………………………………………………11
4.4.1测试……………………………………………………………11
4.4.2问题解决与讨论分析…………………………………………12
4.4.3时间和空间复杂度分析和改进设想…………………………12
4.5附录(原代码及必要注释)………………………………………12
5.总结与展望…………………………………………………………18
参考文献………………………………………………………………19
成绩评定………………………………………………………………19
1.设计时间
2010.12.27—2010.12.31
2.设计目的
通过设计掌握数据结构课程中学到的基本理论和算法并综合运用于解决实践问题中,它是理论与实践的结合。
通过做这个算术表达式求值演示的实验,来使我们对栈有一个更深层次的了解。
3.设计任务
算术表达式求值演示。
设计一个程序,用栈来求解表达式的值,要求以表达式的形式输入,以#号结束,运算符为+-*/(),要有输出结果。
所能达到的功能,做+-*/运算。
4.设计内容
4.1需求分析
4.1.1程序所要实现的功能
实现用栈的入栈出栈演示表达式求值过程。
4.1.2输入形式和输入值的范围
以表达式的形式输入,输入值在0-9之间。
操作符的范围——+-*/()
4.1.3输出形式
输出的形式以#号结束。
4.1.4测试数据:
正确测试:
能以正确的形式输出。
错误测试:
不能输出正确的结果,只能输出个错误的表达式。
4.2总体设计
4.2.1设定栈的抽象数据类型定义:
ADTStack{
数据对象:
D={ai|ai∈ElemSet,i=1,2,...,n,n≥0}
数据关系:
R1={|ai-1,ai∈D,i=2,...,n}
约定an端为栈顶,a1端为栈底。
基本操作:
InitStack(&S)
操作结果:
构造一个空栈S。
GetTop(S,&e)
初始条件:
栈S已存在且非空。
操作结果:
用e返回S的栈顶元素。
Push(&S,e)
初始条件:
栈S已存在。
操作结果:
插入元素e为新的栈顶元素。
StackEmpty(S)
初始条件:
栈S已存在。
操作结果:
若栈S为空栈,则返回TRUE,否则FALE。
Pop(&S,&e)
初始条件:
栈S已存在且非空。
操作结果:
删除S的栈顶元素,并用e返回其值。
}ADTStack
4.2.2主程序流程:
InitStack(Stack*s)和InitStack2(Stack2*s)分别构造运算符栈与构造操作数栈,Push(Stack*s,charch)运算符栈插入ch为新的栈顶元素,Push2(Stack2*s,intch)操作数栈插入ch为新的栈顶元素,Pop(Stack*s)删除运算符栈s的栈顶元素,用p返回其值,Pop2(Stack2*s)删除操作数栈s的栈顶元素,用p返回其值,GetTop(Stacks)用p返回运算符栈s的栈顶元素,GetTop2(Stack2s)用p返回操作数栈s的栈顶元素。
(1)In(charch)判断字符是否是运算符功能,运算符即返回1,该功能
(2)Precede(charc1,charc2)判断运算符优先权功能,该函数判断运算符c1,c2的优先权。
(3)Operate(inta,charop,intb)操作数用对应的运算符进行运算功能。
运算结果直接返回。
(4)num(intn)求操作数的长度功能,需要用itoa函数把int型转换成字符串型,strlen函数可求字符长度。
(5)EvalExpr()主要操作函数运算功能。
(1)、主程序模块
voidmain()
{
structSqstackopnd;//操作数栈
structSqstackoptr;//操作符栈
elemtyperesult;
result=evaluate(opnd,optr);
printf("theresultis%d\n",result);
}
(2)运算模块——实现数据表达式的运算
(3)栈模块——实现栈抽象数据类型
4.2.3模块调用关系:
主模块先调用expr函数,之后依次调InitStack(&OPTR);Push(&OPTR,'#');InitStack2(&OPND);最后调用运算模块EvalExpr()。
4.3详细设计:
4.3.1数据类型的实现
因为表达式是由操作符,运算符和界限符组成的。
如果只用一个char类型栈,不能满足2位以上的整数,所以还需要定义一个int类型的栈用来寄存操作数。
/*定义字符类型栈*/
typedefstruct{
intstacksize;
char*base;
char*top;
}Stack;
/*定义整型栈*/
typedefstruct{
intstacksize;
int*base;
int*top;
}Stack2;
4.3.2主程序和其他主要函数的伪码:
1、Precede(charc1,charc2)判断运算符优先权,返回优先权高的。
算符间的优先关系如下:
+
-
*
/
(
)
#
+
>
<
<
<
<
>
>
-
>
>
<
<
<
>
>
*
>
>
>
>
<
>
>
/
>
>
>
>
<
>
>
(
<
<
<
<
<
=
)
>
>
>
>
>
>
#
<
<
<
<
<
=
表1
算法伪代码如下:
charPrecede(charc1,charc2)
{
staticchararray[49]={
'>','>','<','<','<','>','>',
'>','>','<','<','<','>','>',
'>','>','>','>','<','>','>',
'>','>','>','>','<','>','>',
'<','<','<','<','<','=','!
',
'>','>','>','>','!
','>','>',
'<','<','<','<','<','!
','='};//用一维数组存储49种情况
switch(c1)
{
/*i为下面array的横标*/
case'+':
i=0;break;
case'-':
i=1;break;
case'*':
i=2;break;
case'/':
i=3;break;
case'(':
i=4;break;
case')':
i=5;break;
case'#':
i=6;break;
}
switch(c2)
{
/*j为下面array的纵标*/
case'+':
j=0;break;
case'-':
j=1;break;
case'*':
j=2;break;
case'/':
j=3;break;
case'(':
j=4;break;
case')':
j=5;break;
case'#':
j=6;break;
}
return(array[7*i+j]);/*返回运算符array[7*i+j]为对应的c1,c2优先关系*/
}
2.intEvalExpr()主要操作函数。
算法概要流程图:
利用该算法对算术表达式3*(7-2)求值操作过程如下:
步骤
OPTR栈
OPND栈
输入字符
主要操作
1
#
3*(7-2)#
Push(OPND,’3’)
2
#
3
*(7-2)#
Push(OPTR,’*’)
3
#*
3
(7-2)#
Push(OPNR,’(’)
4
#*(
3
7-2)#
Push(OPND,’7’)
5
#*(
37
-2)#
Push(OPNR,’-’)
6
#*(-
37
2)#
Push(OPND,’2’)
7
#*(-
372
)#
Operate(‘7’,’-’,’2’)
8
#*(
35
)#
Pop(OPTR)
9
#*
35
#
Operate(‘3’,’*’,5’)
10
#
15
#
Return(GetTop2(OPND))
表2
intEvalExpr(void)
{
charc,theta,x,m,ch;
inta,b;
c=*ptr++;
while(c!
='#'||GetTop(OPTR)!
='#')
if(!
In(c))
{
m=atoi(&c);
Push(&OPND,m);
c=*ptr++;
}
else
switch(Precede(GetTop(OPTR),c))
{
case'<':
Push(&OPTR,c);
c=*ptr++;
break;
case'=':
x=Pop(&OPTR);
c=*ptr++;
break;
case'>':
theta=Pop(&OPTR);
b=Pop(&OPND);a=Pop(&OPND);
Push(&OPND,Operate(a,theta,b));
break;
}
returnGetTop(OPND);
}
主函数:
intmain(void)
{
char*pc;
printf("请输入要求的表达式并以"#"结尾:
");
gets(expr);
pc=expr;
if(expr[0]=='\0')
{
printf("请输入一个有效的表达式以#号结束\n");
printf("请再次输入要求表达式并以“#”结尾:
");
gets(expr);
}
else
{
while(*pc!
='\0')
pc++;
pc--;
if(*pc!
='#')
{
printf("请输入要求的表达式并以"#"结尾:
\n");
printf("请再次输入要求表达式并以“#”结尾:
");
gets(expr);
}
}
4.3.3各函数之间的调用关系:
①输入表达式调用expr;
②表达式的值调用EvalExpr()
算术式运算EvalExpr()用到GetTop,Push,Precede以及Pop函数
4.4测试与分析
4.4.1测试
正确测试:
2*(7-4)#
请输入一个表达式以#号结束:
2*(7-4)#
12PUSH(OPTR,#)
2#*PUSH(OPND,2)
3#2(PUSH(OPTR,*)
4#*27PUSH(OPTR,()
5#*(2-PUSH(OPND,7)
6#*(274PUSH(OPTR,-)
7#*(-27)PUSH(OPND,4)
8#*(-274#POP(OPTR)
9#*(274#POP(OPND)
10#*(27#POP(OPND)
11#*(2#OPERATE(7,-,4)
12#*(2#PUSH(OPND,3)
13#*(23#POP(OPTR)
14#*23
输出结果为:
6
错误测试:
12*6#
请输入一个表达式以#号结束:
12*6#
11PUSH(OPTR,#)
2#2PUSH(OPND,1)
3#1*PUSH(OPND,2)
4#126PUSH(OPTR,*)
5#*12#PUSH(OPND,6)
6#*126
输出结果为:
12
4.4.2问题解决与讨论分析
1、本设计的关键是运算符优先级的判断,由于优先级的错判,很容导致果的运算错误。
要明晰判断当前运算符和运算符栈栈顶元素的先后顺序,这个易出错误。
2、在本次设计中充分利用了,栈先进后出的特点。
3、二位数输入计算。
我们应将二位数转换成一位数,将两个数字做特殊处理,放入同一个栈的同一位置,出栈时同时出栈,并加以计算。
4.4.3时间和空间复杂度分析和改进设想
空间复杂度和时间复杂度由于算术式计算量较小,因此不会占用过多时间复杂度,空间复杂度则决定于操作数与操作符的多少。
改进设想:
运用将一个式子分为多个部分,逐次计算。
4.5附录(原代码及必要注释)
#include
#include
#include
#include
#defineDEBUG
#defineNULL0
#defineERROR-1
#defineSTACKSIZE20
/*定义字符类型栈*/
typedefstruct{
charstackname[20];
char*base;
char*top;
}Stack;
/*-----------------全局变量---------------*/
StackOPTR,OPND;/*定义前个运算符栈,后个操作数栈*/
charexpr[255]="";/*存放表达式串*/
char*ptr=expr;
intstep=0;/*计算的步次*/
intInitStack(Stack*s,char*name)
{
s->base=(char*)malloc(STACKSIZE*sizeof(char));
if(!
s->base)exit(ERROR);
strcpy(s->stackname,name);
s->top=s->base;
return1;
}
intIn(charch)
{
return(ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='('||ch==')'||ch=='#');
}
voidOutputStatus(void)
{
char*s;
/*step*/
printf("\n%-8d",++step);
/*OPTR*/
for(s=OPTR.base;sprintf("%c",*s);
printf("\t");
/*OPND*/
for(s=OPND.base;sprintf("%d",*s);
/*inputchar*/
printf("\t\t%c",*ptr);
}
intPush(Stack*s,charch)
{
#ifdefDEBUG
char*name=s->stackname;
OutputStatus();
if(strcmp(name,"OPND")==0)
printf("\tPUSH(%s,%d)",name,ch);
else
printf("\tPUSH(%s,%c)",name,ch);
#endif
*s->top=ch;
s->top++;
return0;
}
charPop(Stack*s)
{
charp;
#ifdefDEBUG
OutputStatus();
printf("\tPOP(%s)",s->stackname);
#endif
s->top--;
p=*s->top;
return(p);
}
charGetTop(Stacks)
{
charp=*(s.top-1);
return(p);
}
/*判断运算符优先权,返回优行权高的*/
charPrecede(charc1,charc2)
{
inti=0,j=0;
staticchararray[49]={'>','>','<','<','<','>','>',
'>','>','<','<','<','>','>',
'>','>','>','>','<','>','>',
'>','>','>','>','<','>','>',
'<','<','<','<','<','=','!
',
'>','>','>','>','!
','>','>',
'<','<','<','<','<','!
','='};
switch(c1)
{
/*i为下面array的横标*/
case'+':
i=0;break;
case'-':
i=1;break;
case'*':
i=2;break;
case'/':
i=3;break;
case'(':
i=4;break;
case')':
i=5;break;
case'#':
i=6;break;
}
switch(c2)
{
/*j为下面array的纵标*/
case'+':
j=0;break;
case'-':
j=1;break;
case'*':
j=2;break;
case'/':
j=3;break;
case'(':
j=4;break;
case')':
j=5;break;
case'#':
j=6;break;
}
return(array[7*i+j]);/*返回运算符*/
}
/*操作函数*/
intOperate(inta,charop,intb)
{
#ifdefDEBUG
OutputStatus();
printf("\tOPERATE(%d,%c,%d)",a,op,b);
#endif
switch(op)
{
case'+':
return(a+b);
case'-':
return(a-b);
case'*':
return(a*b);
case'/':
return(a/b);
}
return0;
}
intEvalExpr(void)
{
charc,theta,x,m,ch;
inta,b;
c=*ptr++;
while(c!
='#'||GetTop(OPTR)!
='#')
if(!
In(c))
{
m=atoi(&c);
Push(&OPND,m);
c=*ptr++;
}
else
switch(Precede(GetTop(OPTR),c))
{
case'<':
Push(&OPTR,c);
c=*ptr++;
break;
case'=':
x=Pop(&OPTR);
c=*ptr++;
break;
case'>':
theta=Pop(&OPTR);
b=Pop(&OPND);a=Pop(&OPND);
Push(&OPND,Operate(a,theta,b));
break;
}
returnGetTop(OPND);
}
intmain(void)
{
char*pc;
printf("Inputtheexpression(endwith\"#\"sign):
");
gets(expr);
pc=expr;
if(expr[0]=='\0')
{
printf("Pleaseinputavalidexpression!
\n");
printf("Inputtheexpressionagain(endwith\"#\"sign):
");
gets(expr);
}
else
{
while(*pc!
='\0')
pc++;
pc--;
if(*pc!
='#')
{
printf("Pleaseasuretheexpressionendwith\"#\"sign!
\n");
printf("Inputtheexpressionagain(endwith\"#\"sign):
");
gets(expr);
}
}
5.总结与展望
这次课程设计让我有一个深刻的体会,那就是细节决定成败,编程最需要的是严谨,如何的严谨都不过分,往往检查了半天发现错误发生在某个括号,分号,引号,或者数据类型上。
就像我在写EvalExpr()函数时,忘了指针的地址符值不用加*号,这一点小小