算术表达式的求解-数据结构课程设计报告
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
《数据结构》
课程设计报告书
题目:算术表达式的求解
系别:计算机科学与应用
目录
一、需求分析 (3)
1、设计要求: (3)
2、设计构想: (3)
二、概要设计 (4)
1、本程序包含的模块: (4)
三、详细设计 (4)
1、定义栈结构 (5)
2、栈的基本操作 (5)
(1)初始化栈 (5)
(2)入栈 (5)
(3)出栈 (6)
(4)取栈顶元素 (6)
(5)运算模块 (6)
3、判断运算符的优先级 (7)
4、运算函数 (8)
(1) 基础运算函数: (8)
(2)运算函数 (9)
(3)主程序模块 (12)
四、调试分析 (12)
1、测试结果 (12)
2、程序时间复杂度为O(n); (13)
3、设计中出现的问题: (13)
4、算法改进: (14)
五、课程设计总结 (15)
课程设计报告
一、需求分析
1、设计要求:
给定一个算术表达式,通过程序求出最后的结果
1>、从键盘输入要求解的算术表达式;
2>、采用栈结构进行算术表达式的求解过程;
3>、能够判断算术表达式正确与否;
4>、对于错误表达式给出提示;
5>、对于正确的表达式给出最后的结果;
2、设计构想:
为了实现算符优先算法使用两个工作栈,一个称作OPTR,以寄存运算符;另一个称作OPND,用以寄存操作数或运算结果。
在操作数和操作符入栈前,通过一个函数来判别,输入的是操作数还是操作符,操作数入OPND,操作符入OPTR。
在输入表达式的最后输入‘#’,设定‘#’的优先级最低,代表表达式输入结束。
在表达式输入过程中,遇操作数则直接入栈,遇到运算符则与栈顶运算符比较优先级,若当前运算符优先级高,则当前运算符入栈,扫描下一符号;否则栈顶运算符出栈,两操作数出栈,进行运算,所得结果入数栈,重新比较当前运算符与新栈顶运算符。
如此重复直到栈顶运算符与当前符号均为‘#’,运算结束。
二、概要设计
1、本程序包含的模块:
(1)栈模块——实现栈抽象数据类型
(2)运算模块——实现数据表达式的运算(3)主程序模块
三、详细设计
(1)栈模块
1、定义栈结构
struct Sqstack
{
int *top;//栈顶元素
int *base; //栈底元素
int stacksize;//栈的大小
};
2、栈的基本操作
(1)初始化栈
int initstack(struct Sqstack &s)
{
s.base=(int *)malloc(stack_size*sizeof(int));
if(!s.base)
return OVERFLOW;
s.top=s.base;
s.stacksize=stack_size;
return OK;
}
(2)入栈
int push(struct Sqstack &s,int e)
{
if(s.top-s.base>=s.stacksize)
{
s.base=(int*)realloc(s.base,(s.stacksize+stack_increasement)*sizeof(int));
if(!(s.base))
return OVERFLOW;
s.top=s.base+s.stacksize;
s.stacksize+=stack_increasement;
}
* s.top++=e;
return OK;
}
(3)出栈
int pop(struct Sqstack &s)
{
int e;
if(s.top==s.base)
return ERROR;
e=*--s.top;
return e;
}
(4)取栈顶元素
int gettop(struct Sqstack &s)
{
int e;
if(s.top==s.base)
return ERROR;
e=*(s.top-1);
return e;
}
(5)运算模块
1、判断输入字符c是否为操作符:若是,则返回1;否则,返回0
int In(int c)
{
char p[10]="+-*/()#^";
int i=0;
while(p[i]!='\0')
{
if(p[i]==c)
return 1;
i++;
}
return 0;
}
3、判断运算符的优先级
char precede(char top,char c)
//该函数为判断当前运算符与前一个运算符的优先级,前一个运算符高于或等于当前运算符的优先级则返回'>',前一个运算符小于当前运算符的优先级则返'<',当前一个运算符为'('当前运算符为')'时返回'=',用于去除表达式的括号。
{
char result;
switch(c)
{
case '#': result='>'; break;
case '+':
case '-':
if(top=='#'||top=='(')
result='<';
else
result='>'; break;
case '*':
case '/':
if(top=='*'||top=='/'||top=='^')
result='>';
else
result='<'; break;
case '%':
if(top=='%'||top=='/'||top=='^'||top=='*')
result='>';
else
result='<';break;
case ')':
if(top=='(')
result='=';
else
result='>'; break;
case '(': result='<'; break;
case '^': result='<'; break;
default: printf("操作符输入错误!\n");
}
return result;
}
4、运算函数
(1) 基础运算函数:
实现相应的加、减、乘、除、乘方及带小括号的基本数学运算并返回结果,其中a,b为两个操作数,theta为操作符
int operate(int a,char theta,int b)
{
int result;
switch(theta)
{
case '+': result=a+b; break;
case '-': result=a-b; break;
case '*': result=a*b; break;
case '/':
if(b==0)
{
printf("\n\n输入错误!分母不能为0!\n");
result=0;
}
else
result=a/b;break;
case '%':
if(b==0||b==NULL)
{
printf("\n\n输入错误!\n");
return 0;break;
}
else
result=a%b;break;
case '^': result=(int)pow((double)a,(double)b); break;
default: printf("操作符输入错误!\n");
}
return result;
}
(2)运算函数
int evaluate(struct Sqstack opnd,struct Sqstack optr)
//该函数为求表达式的值的整个操作过程,通过调用相应的函数实现遇到运算符则与栈顶运算符比较优先级,
//若当前运算符优先级高(前面的运算还不应执行)则当前运算符入栈,扫描下一符号;否则栈顶运算符出栈,同时两操作数出栈,进行运算,所得结果入数栈, //重新比较当前运算符(注意当前运算符未变)与新栈顶运算符。
如此重复直到栈顶运算符与当前符号均为'#',运算结束。
//若操作数为个位数,则直接将输入的字符减48后入栈,若为多位数,则通过flag来实现。
若输入字符c为操作数且flag=1(即操作数为多位数),则将操作数栈的栈顶元素出栈后乘以10,然后加上,(c-48)然后将二者的和入操作数栈。
{
int a,b,c,theta,e;
initstack(optr);
push(optr,'#');
initstack(opnd);
c=getchar();
int flag=0;
//当输入操作数时flag=1;当输入操作符时flag=0;
//当前输入为操作数且flag=1时,将操作数栈的栈顶元素出栈,然后将其和当前输入转换成相应的int类型
while(c!='#'||gettop(optr)!='#')
{
if(!In(c)) //c若为操作数则入opnd栈
{
if(flag==1)
{
e=pop(opnd); // 取栈顶元素
push(opnd,(e*10+(c-48)));
//将输入数在转化为int型,并将上次输入数*10并与当前操作数相加,将结果如操作数栈
}
else
push(opnd,c-48);
flag=1;
c=getchar();
}
else
{
flag=0;
//当前字符为操作符,则入操作符栈,并将flag置为0
switch(precede(gettop(optr),c))
// 判断当前操作数与操作符栈中的栈顶元素的优先级
{
case '<': push(optr,c); c=getchar(); break;
// 若当前操作符的优先级高于操作符栈的栈顶元素,则将当前操作符入操作符栈
case '=': e=pop(optr); c=getchar(); break;
// 若当前操作符与操作符栈的栈顶元素构成匹配的括号,则//将操作符栈顶元素出栈
case '>': theta=pop(optr); b=pop(opnd); a=pop(opnd); push(opnd,operate(a,theta,b)); break;
// 若当前操作符的优先级低于操作符栈的栈顶元素,则将操作符栈栈顶元素出栈,并将操作数栈的栈顶两个元素出栈,计算两个元素间以操作符栈栈顶元素为运算符的数学运算
}//switch
}//if
}//while
return pop(opnd);
}
(3)主程序模块
1、main函数
void main(int argc,char *argv[])
{
struct Sqstack opnd; //操作数栈
struct Sqstack optr;//操作符栈
initstack(opnd);
initstack(optr);
int result;
printf("**************************************************\n");
printf("算术运算式的求解");
printf("\n************************************************\n");
printf("\n请输入算术运算表达式(以'#'结尾):\n");
printf("\n");
result=evaluate(opnd,optr);
printf("\n************************************************\n");
printf("\n\n运算的结果是 :\n \n%d\n",result);
printf("\n************************************************\n");
}
四、调试分析
1、测试结果
1> 测试数据:6+9-8/2#
测试结果:
2> 测试数据:6+9-8/2#
测试结果:
3> 测试数据: 1/0#
测试结果:
2、程序时间复杂度为O(n);
3、设计中出现的问题:
在开始的设计中没有注意除数不能为0 ,后来加入
if(b==0)
{
printf("分母为0,the result is error\n");
result=0;
}
else
result=a/b;break;来判断除数是否为0
4、算法改进:
1>输入的操作数和操作码由于是字符串类型的,在原设计中实现的操作都是对个位数实现的,实用性不大,故在后来的设计中,通过一个标志flag实现了标志操作数的连续输入的判别,继而实现了多位数的表达式运算
2>开始只实现了加、减、乘、除及带小括号的数学运算,考虑到实用性,在后来的设计中引入pow函数,实现了乘方的运算,调整结果如下:
3>最初设计的运行界面过于单调,不够友好,改进时加入一些*调整
调整结果如下:
五、课程设计总结
在这两周的课程设计中出现很多问题,在不断解决问题的过程中也有了不少的收获。
通过再一次复习并更深入的了解了数据结构及C语言之中的相关知识,通过《算术运算式的求解》这一题目,形象深入的理解了栈结构及原理。
同时,通过每一次的编译运行不断改进完善题目,并通过这一个不断改进的过程,完善自己的思想,增强了自己全面分析问题的能力。
当然,这一次的课程设计我做的还不是足够的好,还有很多的不足之处,缺少经验和实践,但是,我相信,在今后的学习中我会更加注重这方面的培养,加倍努力,珍惜机会,将所学的东西更好的应用到以后的实践中。