版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
合肥学院计算机科学与技术系课程设计报告2009~2010学年第二学期课程数据结构与算法课程设计名称模拟计算器程序学生姓名桂俊飞学号0804012021专业班级08计本〔2〕班指导教师王昆仑张贯虹2010年6月一:问题分析和任务定义本程序写的是模拟计算器。要求设计一个模拟计算器的程序,要求对包含加、减、乘、除、括号运算符及SQR和ABS函数的任意整型表达式进行求解。这里可以做一个扩展,比方实现求某数的N次方,求模,一些常用的三角函数等。这个程序实际上就是对一个表达式进行计算。而一个算术表达式中包含各种运算符,每个运算符的等级可能会不同,这就成了本程序需要解决的一个主要的问题之一了。另外计算器中需要有各种数学函数,比方:abssqrtsincostan等,如何对这些函数进行处理,也是本程序能成功的一个关键。还有一个问题就是如何处理操作符和操作数之间的关系也是一个要点。例如:1+2*(3-2/1),经过怎么样的变换和处理能得出结果5。数据的输入这里应该要用字符,然后通过字符和整形之间的关系进行转换即可,这样处理的话,就方便很多了。二:概要设计和数据结构选择输入的时候将一个算术表达式用一个字符数组来接收,故需要对这个数组进行处理,让操作数和操作符分开,这里我想把开始的算术表达式转换成一个后缀表达式,这样在进行计算的时候就简单多了。而在转换的过程中,对运算符的处理极为重要,这里运用堆栈,用堆栈的先进后出的特点,来处理运算符优先级的问题,让其成功转换成后缀表达式。而在对后缀表达式进行处理的时候,又需要一个堆栈,这个堆栈存放操作数的。并将运算结果存入该栈中。两个堆栈的数据结构如下:struct{chardata[Maxlen];inttop;}optr;//定义运算符栈struct{doubledata[Maxlen];inttop;}opnd;//定义操作数栈这里定义了类型,并且一起定义了两者类型的对象optr,opnd。在将算术表达式转换成后缀表达式,定义change函数;在对后缀表达式进行处理时,定义jisuan函数,另外本程序有个欢送界面,由meun函数实现。因此主函数于各函数之间的关系为:meun()main()change()jisuan()本程序实现的流程:这里的两个主要的函数具体算法在详细设计中有说明。三:详细设计和编码首先定义两个数组,p[400]用来存放算术表达式,q[400]用来存放后缀表达式。由前面的数据结构定义两个对象optr,opnd。当输入一个表达式后,定义i作为q的下标,定义dh=1表示是负号,初始化运算符栈optr.top=-1;让后对p进行扫描,当p指向的为数字字符,那么将此字符如q,后在往q中输入#,具体为:while(*p>='0'&&*p<='9') {q[i]=*p;i++;p++;}if(*p=='.') {q[i]='.';i++;p++;while(*p>='0'&&*p<='9'){q[i]=*p;i++;p++;}}q[i]='#';i++;dh=0;p后移,继续扫描,当遇到+或-时,执行if(dh==1){if(*p=='-')optr.top++;optr.data[optr.top]='@';p++;break;}while(optr.top!=-1&&optr.data[optr.top]!='(') {q[i]=optr.data[optr.top];optr.top--;i++; }optr.top++;optr.data[optr.top]=*p;p++;dh=0;break;当遇到*或/时,先查看操作符栈中是否有优秀级比它大的或者一样大的运算符,有的话就将其他的出栈,最后自己入栈。执行:while(optr.data[optr.top]=='*'||optr.data[optr.top]=='/'||optr.data[optr.top]=='s') {q[i]=optr.data[optr.top];optr.top--;i++;} optr.top++;optr.data[optr.top]=*p;p++;dh=0;break;当遇到〔时,此时不需要别的其他的操作,只需将其入操作符栈,并将dh=0;当遇到〕时,此时需要将〔之前的操作符全部出栈,具体操作如下:while(optr.data[optr.top]!='(') {q[i]=optr.data[optr.top];optr.top--;i++;} optr.top--;p++;dh=0;break;当遇到^时,根据运算符的优先级,执行:while(optr.data[optr.top]=='^') {q[i]=optr.data[optr.top];optr.top--;i++;} optr.top++;optr.data[optr.top]=*p;p++;dh=0;break;遇到%时的操作和^差不多,这里就不做介绍了。当遇到数学函数的相关符号时,这里以sin为例,当扫描s时,还需要扫描后面的两个字符,当它们是in时,说明就是sin函数的符号,此时将此函数的标志入操作符栈,当其为qrt时,说明是sqrt函数,此时将sqrt函数的标志入栈,这里的标志是自己定的。如果都不是上面两种情况,说明输入有误,跳回。具体的程序如下:if((*(p+1)=='i'||*(p+1)=='I')&&(*(p+2)=='n'||*(p+2)=='N')){optr.top++;optr.data[optr.top]='s';p+=3;dh=0;break;} elseif((*(p+1)=='q'||*(p+1)=='Q')&&(*(p+2)=='r'||*(p+2)=='R')&&(*(p+3)=='t'||*(p+3)=='T')) {optr.top++;optr.data[optr.top]='q';p+=4;dh=0;break; }else{cout<<endl<<"有错误符号"<<endl;returnerror;}其他的数学函数的操作都是类似的,这里就不一一说明了。这里值得注意的是,当将p扫描完时,操作符栈并未一定为空,故需要将操作符栈里的数据全部出栈:while(optr.top!=-1) {q[i]=optr.data[optr.top];i++;optr.top--;}以上是将算术表达式转换成后缀表达式。还要对后缀表达式进行计算,才能得到结果。首先还是对表达式进行扫描,遇到数字符时,先将其转换成整形后,再判断是否有小数点存在,继续扫描直到遇到运算符,让后通过运算,将次数转换成小数,最后入栈。具体程序实现:d=0;while(*q>='0'&&*q<='9') {d=10*d+(*q-'0');q++;}x=0.1;if(*q=='.'){q++;while(*q>='0'&&*q<='9'){d=d+x*(*q-'0');x*=0.1;q++;}}当遇到操作符时,为双目运算符时,只需要将操作数栈的栈顶和次栈顶数拿出来进行相应的计算,并将其压入次栈顶。为单目运算符时,只需将操作数栈顶元素进行运算即可,并将运算符压入栈即可。这里以/和sin为例。其余的均和此类似。if(opnd.data[opnd.top]!=0)opnd.data[opnd.top-1]=opnd.data[opnd.top-1]/opnd.data[opnd.top];else{cout<<endl<<"除数不能为零!"<<endl;returnerror;}和opnd.top--;break;opnd.data[opnd.top]=sin(opnd.data[opnd.top]);当q都扫描完时,返回操作数栈顶元素就是计算的结果。四:上机调试在语法上的错误,出现过很多,比方少了一个括号,少了个分号,这些问题都是日常写程序中经常出现的问题,想要防止有点难,不过这些错误根据编译器的提示和警告,就能很快的该出来。就图1中出现的问题,这个问题是在#defineerror1234567时出现的,这个问题我一直想不同,我定义123456789时可以通过编译,而变成1234567就不行了,通过向老师请教,发现这里的error和编译器里的定义重合了,故不能通过。解决方法是将这里的error改成derror,这样在函数中error相应的也要该。在逻辑上的错误,主要就是算法中出现的问题,本程序中的算法有点复杂,在表达式转换成后缀表达式的过程中就出现了很多的错误。这里举出一个简单的错误,由于本程序在写的时候,定义了derror=1234567在程序中就不能出现这个计算结果,虽然它超过了本程序的能处理的范围,可是其结果还是1234567,故返回主函数时,在if(change(p,q)==1){k=jisuan(q); if(k==derror) cout<<"";else cout<<"计算结果为:"<<k<<endl; }这里就会出错。导致图中的错误。解决方法,这里我对这中情况没有做特殊的处理。应为在实际的运算过程中,很少有1234567这个结果出现,几乎是不出现的。如何去定义这个数,一直是个问题。本程序的,在定义的时用了两个数组,故其空间复杂度是n,在算法上,这里我用了一个死循环,当输入不为0时,会一直运行。所以只讨论运行一次的时间复杂度。在转换的函数中,有个while()循环,这里的复杂度是n,而在这个循环里,还存在while()循环,故其时间复杂度是n的平方。在计算函数中,其复杂度也是n的平方。故可知本程序的时间复杂度是n平方。经验和体会:这个程序我一直是很简单的,因为我很久之前就在一直考虑这个问题,但是没有去实现过,以为很简单,可是当真正写起来的时候,发现有点困难。开始的时候用书山的那种方法,可是发现那种方法不适合我,不是有多难,就是我的大脑反响不过来。后来想到用后缀表达式,这样处理起来就方便多了,思路也清晰了很多。在不断的错误中改错,在调试中发现程序中的逻辑错误并改正错误。终于这个程序完成了,心中不免有中自豪感。五:用户使用说明本程序用vc++6.0编的,在DOS界面下运行的。运行时,程序有个欢送的界面,并提示输入表达式,在输入时要注意的是,本程序能处理的数据长度最长为6位。另外,输入0时,结束本程序;如输入的表达式有错误的符号时,程序提示输入错误;当输入正确时,按回车键,即可得到计算结果。六:测试结果经过人工计算,可知以上结果是正确的。参考文献:[1]王昆仑,李红.数据结构与算法.北京:中国铁道出版社,2006年5月。[2]郑莉,董渊,张瑞丰c++语言程序设计北京:清华大学出版社,2004七:附录〔源程序代码〕#include"iostream"#include"math.h"#include"string"#include"stdlib.h"#include"windows.h"#definederror1234567#defineMaxlen400usingnamespacestd;struct{chardata[Maxlen];inttop;}optr; //定义运算符栈,并定义全局变量struct{doubledata[Maxlen];inttop;}opnd; //定义操作数栈,并定义全局变量voidmain(){charp[400],q[400];doublek;voidmeun(); //声明菜单函数intchange(char*p,charq[]); //声明转换函数doublejisuan(char*q); //声明计算函数meun();for(;;) //循环执行{cout<<"请输入:";cin>>p;if(strcmp(p,"0")==0)return;if(change(p,q)==1){k=jisuan(q); if(k==derror) cout<<"";else cout<<"计算结果为:"<<k<<endl; }system("pause");//控制输出格式system("cls");meun();}}voidmeun(){system("color0a");cout<<"\t\t**************************************"<<endl;cout<<"欢送使用本计算器"<<endl;cout<<"\t\t**************************************"<<endl;cout<<endl;cout<<"按0结束本程序"<<endl;}intchange(char*p,charq[])//将算术表达式p转换成表达式后缀表达式q{inti=0;//i作为q的下标intdh=1;//dh=1表示是负号optr.top=-1;//初始化运算符栈while(*p!='\0')//p表达式未扫描完时循环{switch(*p)//判断各种情况,并做相应的处理 {case'(':optr.top++;optr.data[optr.top]=*p;dh=1;p++;break;case')':while(optr.data[optr.top]!='(') {q[i]=optr.data[optr.top];optr.top--;i++; }optr.top--;p++;dh=0;break;case'+':case'-':if(dh==1)//+,-是正负号 {if(*p=='-')optr.top++;optr.data[optr.top]='@';p++;break; }while(optr.top!=-1&&optr.data[optr.top]!='(') {q[i]=optr.data[optr.top];optr.top--;i++; }optr.top++;optr.data[optr.top]=*p;p++;dh=0;break;case'*':case'/':while(optr.data[optr.top]=='*'||optr.data[optr.top]=='/'||optr.data[optr.top]=='s') {q[i]=optr.data[optr.top];optr.top--;i++; }optr.top++;optr.data[optr.top]=*p;p++;dh=0;break;case'^':while(optr.data[optr.top]=='^') {q[i]=optr.data[optr.top];optr.top--;i++; }optr.top++;optr.data[optr.top]=*p;p++;dh=0;break;case'%':while(optr.data[optr.top]=='%') {q[i]=optr.data[optr.top];optr.top--;i++; }optr.top++;optr.data[optr.top]=*p;p++;dh=0;break;case'':p++;break;//消除空格case's':case'S':if((*(p+1)=='i'||*(p+1)=='I')&&(*(p+2)=='n'||*(p+2)=='N')) {optr.top++;optr.data[optr.top]='s';p+=3;dh=0;break; }elseif((*(p+1)=='q'||*(p+1)=='Q')&&(*(p+2)=='r'||*(p+2)=='R')&&(*(p+3)=='t'||*(p+3)=='T')) {optr.top++;optr.data[optr.top]='q';p+=4;dh=0;break; }else{cout<<endl<<"有错误符号"<<endl;returnderror;}case'c':case'C':if((*(p+1)=='o'||*(p+1)=='O')&&(*(p+2)=='s'||*(p+2)=='S')) {optr.top++;optr.data[optr.top]='c';p+=3;dh=0;break; }else{cout<<endl<<"有错误符号"<<endl;returnderror;}case'T':case't':if((*(p+1)=='a'||*(p+1)=='A')&&(*(p+2)=='n'||*(p+2)=='N')) {optr.top++;optr.data[optr.top]='t';p+=3;dh=0;break; }else{cout<<endl<<"有错误符号"<<endl;;returnderror;}case'e':case'E':if((*(p+1)=='x'||*(p+1)=='X')&&(*(p+2)=='p'||*(p+2)=='P')) {optr.top++;optr.data[optr.top]='e';p+=3;dh=0;break; }else{cout<<endl<<"有错误符号"<<endl;returnderror;}case'a':case'A':if((*(p+1)=='b'||*(p+1)=='B')&&(*(p+2)=='s'||*(p+2)=='S')) {optr.top++;optr.data[optr.top]='a';p+=3;dh=0;break; }else{cout<<endl<<"有错误符号"<<endl;returnderror;}default:while(*p>='0'&&*p<='9')//判断是否为数字 {q[i]=*p;i++;p++; }if(*p=='.') {q[i]='.';i++;p++;while(*p>='0'&&*p<='9') {q[i]=*p;i++;p++;} }q[i]='#';i++;dh=0;//用#标识一个数值串结束 } }while(optr.top!=-1)//此时p扫描完毕,栈不空时循环 {q[i]=optr.data[optr.top];i++;optr.top--; }q[i]='\0';//给q表达式添加结束标识return1;}doublejisuan(char*q)//计算后缀表达式的值{doubled,x;opnd.top=-1;//初始化操作数栈while(*q!='\0')//q字符串未扫描完时循环{switch(*q)//判断各种情况,并做相应的运算,并入栈{case'+':opnd.data[opnd.top-1]=opnd.data[opnd.top-1]+opnd.data[opnd.top];opnd.top--;break;case'-':opnd.data[opnd.top-1]=opnd.data[opnd.top-1]-opnd.data[opnd.top];opnd.top--;break;case'*':opnd.data[opnd.top-1]=opnd.data[opnd.top-1]*opnd.data[opnd.top];opnd.top--;break;case'/':if(opnd.data[opnd.top]!=0)opnd.data[opnd.top-1]=opnd.data[opnd.top-1]/opnd.data[opnd.top];else {cout<<endl<<"除数不能为零!"<<endl;returnderror; }opnd.top--;break;case'^':opnd.data[opnd.top-1]=pow(opnd.data[opnd.top-1],opnd.data[opnd.top]);opnd.top--;break;case
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- GB/T 44769-2024能源互联网数据平台技术规范
- 文书模板-新型智慧城市运行中心建设情况报告
- 元素与物质分类-2023年中考化学一轮复习(解析版)
- 济宁2024年统编版小学6年级上册英语第三单元真题
- 2024-2025学年江苏省镇江某中学高二(上)月考物理试卷(10月)(含答案)
- DB4107T 501-2024 知识产权保护中心服务规范 一般要求
- 五年级科学下册期末试题分类汇编:地表缓慢变化
- 2024年锅炉自控优化装置项目投资申请报告代可行性研究报告
- 2024年安全员C证考试100题及解析
- 纤维增强复合材料防眩格栅技术规范(征求意见稿)
- 软件正版化培训课件
- 2023年上海市徐汇区中考一模英语试卷(附听力音频)含详解
- 普外科科室医疗质量持续改进记录
- 原发性肝癌介入治疗(TACE)临床路径
- 丰田锋兰达保养手册
- 设备签收单模版
- 2023中国建筑行业装配式建筑发展研究报告
- 建设工程监理费计算器(免费)
- 预防校园欺凌、预防校园性侵告家长书
- 软件系统项目监理报告
- 建筑工程施工检测试验计划
评论
0/150
提交评论