资源描述
软件技术基础实验报告
实验名称: 表达式计算器
系 别: 通信工程 ﻫ
年 级:
ﻫ 班 级:
ﻫ 学生学号:
学生姓名:
《数据结构》课程设计报告
题目 简易计算表达式得演示
【题目要求】ﻫﻫ要求:实现基本表达式计算得功能
输入:数学表达式,表达式由整数与“+”、 “—”、“×”、“/”、“(”、“)”组成ﻫ输出:表达式得值ﻫ基本操作:键入表达式,开始计算,计算过程与结果记录在文档中ﻫ难点:括号得处理、乘除得优先级高于加减
1.前言
在计算机中,算术表达式由常量、变量、运算符与括号组成.由于不同得运算符具有不同得优先级,又要考虑括号,因此,算术表达式得求值不可能严格地从左到右进行。因而在程序设计时,借助栈实现。
算法输入:一个算术表达式,由常量、变量、运算符与括号组成(以字符串形式输入)。为简化,规定操作数只能为正整数,操作符为+、—*、/、=,用#表示结束.
算法输出:表达式运算结果。
算法要点:设置运算符栈与运算数栈辅助分析算符优先关系。在读入表达式得字符序列得同时,完成运算符与运算数得识别处理,以及相应运算.
2.概要设计
2、1 数据结构设计
任何一个表达式都就是由操作符,运算符与界限符组成得。我们分别用顺序栈来寄存表达式得操作数与运算符.栈就是限定于紧仅在表尾进行插入或删除操作得线性表。顺序栈得存储结构就是利用一组连续得存储单元依次存放自栈底到栈顶得数据元素,同时附设指针top指示栈顶元素在顺序栈中得位置,base为栈底指针,在顺序栈中,它始终指向栈底,即top=base可作为栈空得标记,每当插入新得栈顶元素时,指针top增1,删除栈顶元素时,指针top减1。
2、2 算法设计
为了实现算符优先算法。可以使用两个工作栈。一个称为OPTR,用以寄存运算符,另一个称做OPND,用以寄存操作数或运算结果。
1、首先置操作数栈为空栈,表达式起始符”#”为运算符栈得栈底元素;
2、依次读入表达式,若就是操作符即进OPND栈,若就是运算符则与OPTR栈得栈顶运算符比较优先权后作相应得操作,直至整个表达式求值完毕(即OPTR栈得栈顶元素与当前读入得字符均为”#")。
2、3 ADT描述
ADT Stack{
数据对象:D={ |∈ElemSet,i=1,2,…,n, n≧0}
数据对象:R1={〈>|,,i=2,…,n}
约定端为栈顶,端为栈底。
基本操作:
InitStack(&S)
操作结果:构造一个空栈S。
GetTop(S)
初始条件:栈S已存在。
操作结果:用P返回S得栈顶元素。
Push(&S,ch)
初始条件:栈S已存在。
操作结果:插入元素ch为新得栈顶元素。
Pop(&S)
初始条件:栈S已存在。
操作结果:删除S得栈顶元素。
In(ch)
操作结果:判断字符就是否就是运算符,运算符即返回1。
Precede(c1, c2)
初始条件:c1,c2为运算符。
操作结果:判断运算符优先权,返回优先权高得。
Operate(a,op,b)
初始条件:a,b为整数,op为运算符。
操作结果:a与b进行运算,op为运算符,返回其值.
num(n)
操作结果:返回操作数得长度。
EvalExpr()
初始条件:输入表达式合法.
操作结果:返回表达式得最终结果。
}ADT Stack
2、4 功能模块分析
1、栈得基本功能。
InitStack(Stack *s) 与InitStack2(Stack2 *s)分别构造运算符栈与构造操作数栈,
Push(Stack *s,char ch) 运算符栈插入ch为新得栈顶元素,
Push2(Stack2 *s,int ch) 操作数栈插入ch为新得栈顶元素,
Pop(Stack *s) 删除运算符栈s得栈顶元素,用p返回其值,
Pop2(Stack2 *s)删除操作数栈s得栈顶元素,用p返回其值,
GetTop(Stack s)用p返回运算符栈s得栈顶元素,
GetTop2(Stack2 s) 用p返回操作数栈s得栈顶元素。
2、其它功能分析。
(1)In(char ch) 判断字符就是否就是运算符功能,运算符即返回1,该功能只需简单得一条语句即可实现,return(ch==’+’||ch==’-'||ch==’*'||ch=='/'||ch=='('||ch==')'||ch=='#’).
(2) Precede(char c1,char c2) 判断运算符优先权功能,该函数判断运算符c1,c2得优先权,具体优先关系参照表1.
(3) Operate(int a,char op,int b)操作数用对应得运算符进行运算功能。运算结果直接返回。
(4) num(int n) 求操作数得长度功能,需要用itoa函数把int型转换成字符串型,strlen函数可求字符长度.
(5) EvalExpr()主要操作函数运算功能。分析详细见“3、详细设计…3、2”。
3。详细设计
3、1 数据存储结构设计
因为表达式就是由操作符,运算符与界限符组成得。如果只用一个char类型栈,不能满足2位以上得整数,所以还需要定义一个int类型得栈用来寄存操作数.
/* 定义字符类型栈 */
struct stacklifei1 //数字栈得定义
{
ﻩdouble *base;
double *top;
}s1;/
struct stacklifei2 //运算符栈得定义
{
ﻩchar *base;
ﻩchar *top;
}s2;
3、2 计算功能得实现
void jisuan() // 该函数对数字栈得前两个栈顶
//元素与符号栈得栈顶元素完成一次运算操作
{
ﻩdouble a,b;
b=*(s1、top—1);
s1、top-—;
ﻩif(s1、top==s1、base)
{
ﻩ error=1;
ﻩﻩreturn ;
ﻩ}
ﻩa=*(s1、top-1);
ﻩswitch(*(s2、top-1))
ﻩ{
case ’+':a=a+b;break;
case '-’:a=a-b;break;
ﻩcase '*':a=a*b;break;
ﻩcase '/':if(b==0){error=2;s2、top=s2、base;return ;}//除数不为0
ﻩ else a=a/b;break;
default :error=1;
ﻩ}
ﻩfprintf(file,"%lf %c %lf= %lf\n",*(s1、top-1),*(s2、top—1),b,a);
ﻩ*(s1、top-1)=a; //将运算结果入栈
s2、top-—;
ﻩreturn ;
}
3、3函数表达式求值功能得实现
void qiuzhi(char *cr)
该函数完成对表达式得处理
{
int i=0,k,h,flag,fuhao=0;
ﻩdouble sum,j;
ﻩs1、base=s1、top=shuzhi;
ﻩs2、base=s2、top=fuha;
ﻩ*(s2、top)='#’;
ﻩs2、top++;
while(s2、top!=s2、base)
ﻩ{
ﻩﻩsum=0;
flag=0;
ﻩﻩk=10;j=1;h=1;
ﻩwhile(cr[i]〉=’0’&&cr[i]<='9'||cr[i]=='、’)
ﻩﻩ //若当前得字符就是数字,就将char型得数据转换为double型
ﻩ{
ﻩ if(cr[i]=='、’)
ﻩﻩﻩ{
ﻩﻩﻩif(cr[i-1]<'0'||cr[i—1]>’9’||i==0||cr[i+1]〈'0'||cr[i+1]>'9')
ﻩ ﻩ{error=1;break;}
ﻩ ﻩelse
ﻩ {k=1;h=10;}
ﻩﻩ }
ﻩﻩ else
ﻩ {
ﻩ ﻩflag=1;j=j*h;
ﻩ ﻩﻩsum=sum*k+(cr[i]-48)/j; ﻩ
ﻩ ﻩ}
ﻩ i++;
ﻩﻩ}
3、4对函数表达式每个字符得操作
switch(cr[i])
ﻩ {
ﻩcase '-’:if(cr[i-1]=='(’||i==0){fuhao=1;i++;break;}
ﻩﻩﻩ //判断就是不就是负号,若不就是则进行与加号相同得操作
//当'-'出现在表达式第一位或就是'(’后第一位,则应将其判为负号
ﻩﻩ case '+':
ﻩ //加、减号得优先级只比'('与’='高,若栈顶元素为这两者之一
ﻩ ﻩﻩ//就将其入栈,否则执行运算操作
ﻩ ﻩif(*(s2、top—1)=='('||*(s2、top-1)=='#’)
ﻩﻩ ﻩ{
ﻩﻩﻩﻩ *(s2、top)=cr[i];
ﻩﻩ ﻩﻩs2、top++;
ﻩﻩﻩi++;
ﻩﻩ }
ﻩ else jisuan();break;
ﻩﻩ case ’*':
ﻩ ﻩcase '/':
ﻩ ﻩ //乘、除号得优先级只比'*’、'/'与'^'低,若栈顶元素为这三者之一
ﻩﻩ//就执行运算操作,否则将其入栈
ﻩ if(*(s2、top-1)=='*'||*(s2、top-1)=='/')jisuan();
ﻩ ﻩelse
ﻩ ﻩ{
ﻩ ﻩ ﻩ*(s2、top)=cr[i];
ﻩﻩﻩ ﻩs2、top++;
ﻩi++;
ﻩ}break;
case '(’: *(s2、top)=cr[i]; s2、top++;i++;break;
ﻩﻩ//未入栈时'('得优先级最高,所以它一定要入栈
ﻩ//但一入栈其优先级就应降为最低
ﻩ ﻩcase ')':
ﻩﻩ //注意:由于'()’运算优先级最高故我直接进行运算,
ﻩﻩ ﻩ//直到栈顶元素为’('后将'('出栈,故符号栈中一定没有')’,
ﻩ ﻩ//这也就是我进行以上优先级判断得前提
ﻩﻩﻩﻩif(*(s2、top-1)==’(')
ﻩﻩ ﻩ{
ﻩﻩ ﻩs2、top--;
ﻩ ﻩ i++;
ﻩﻩﻩﻩ}
ﻩ ﻩelse jisuan();break;
ﻩ ﻩcase ’=’:
ﻩﻩ//表达式结束,若符号栈栈顶元素不为'#',进行运算
ﻩ//否则退栈,结束
ﻩ ﻩif(*(s2、top—1)==’#’)
ﻩﻩﻩﻩ{
ﻩﻩﻩs2、top-—;
ﻩﻩ }
ﻩﻩﻩﻩelse jisuan();break;
ﻩdefault :i++; //清除空格及未定义符号
}
3、5主菜单页面得实现
void main()
{
char cr[60];
char c='a';
ﻩ(outfile,"w+");
//使用提示
printf("*******************************************************************************\n");
ﻩprintf("*********************************李斐计算器************************************\n”);
ﻩprintf("四则简易计算器\n\n");
printf("输入表达式例如 2+4= \n\n");
ﻩprintf("最后按 # 键 则会退出保存\n\n");
ﻩprintf("谢谢使用\n\n");
ﻩprintf("---——---———--—-——----—-——------—--———---—--——————--——————-——-—--——-———-—--————\n");
ﻩprintf("******************************************************************************\n");
ﻩ//循环输入表达式,按’#'键退出
while(c!=’#’)
{
ﻩerror=0;
ﻩﻩprintf(”输入表达式:\n");
ﻩ gets(cr);
ﻩfprintf(file,”表达式:%s\n",cr);
qiuzhi(cr);
ﻩ printf(”任意键继续,按 # 键退出:\n");
c=getch();
}
fclose(file);
}
【附加一】 算符间得优先关系如下:
+
-
*
/
(
)
=
#
+
〉
〈
〈
<
〈
>
>
>
—
>
〉
〈
<
<
>
〉
>
*
〉
>
>
〉
<
〉
>
〉
/
〉
〉
>
>
<
〉
>
>
(
<
〈
<
<
<
=
>
>
)
>
>
〉
>
=
>
>
>
=
<
<
〈
<
<
<
=
<
#
<
〈
<
〈
<
<
>
=
4.软件测试
1、运行成功后界面。
2、输入正确得表达式后.
3、更改表达式,带括号输出
5。心得体会
这次课程设计让我再一次加了解大一学到得C与这个学期学到得数据结构。课设题目要求不仅要求对课本知识有较深刻得了解,同时要求程序设计者有较强得思维与动手能力与更加了解编程思想与编程技巧。
这次课程设计让我有一个深刻得体会,那就就是细节决定成败,编程最需要得就是严谨,如何得严谨都不过分,往往检查了半天发现错误发生在某个括号,分号,引号,或者数据类型上.就一点小小得错误也耽误了我几十分钟,所以说细节很重要。
程序设计时,也不要怕遇到错误,在实际操作过程中犯得一些错误还会有意外得收获,感觉课程设计很有意思。在具体操作中这学期所学得数据结构得理论知识得到巩固,达到课程设计得基本目得,也发现自己得不足之出,在以后得上机中应更加注意,同时体会到C语言具有得语句简洁,使用灵活,执行效率高等特点。发现上机得重要作用,特别算术表达式有了深刻得理解.
最后,感谢老师在这门数据结构课程得悉心指导,祝老师与助教身体健康,万事如意!
【参考文献】
1、《数据结构(C语言版)》 严蔚敏 清华大学出版社
2、《C程序设计》 谭浩强 清华大学出版社
【附 录】
程序源代码:
#include<stdio、h〉
#include<stdlib、h>
#include<math、h>
#include〈conio、h>
struct stacklifei1 //数字栈得定义
{
ﻩdouble *base;
double *top;
}s1;
struct stacklifei2 //运算符栈得定义
{
char *base;
char *top;
}s2;
double shuzhi[40]; //数字栈
char fuha[40]; //符号栈
int error; //出错标识符
FILE *file;
char out]="\lifeijisuanqi、txt";
void jisuan() // 该函数对数字栈得前两个栈顶
//元素与符号栈得栈顶元素完成一次运算操作
{
ﻩdouble a,b;
ﻩb=*(s1、top-1); //取数字栈栈顶元素
s1、top-—;
if(s1、top==s1、base)
ﻩ{
ﻩ error=1;
ﻩﻩreturn ;
ﻩ} //若栈空,出错
a=*(s1、top-1); //取数字栈栈顶元素
ﻩswitch(*(s2、top-1))
ﻩ{
ﻩcase '+':a=a+b;break;
ﻩcase ’-':a=a—b;break;
ﻩcase ’*':a=a*b;break;
case ’/':if(b==0){error=2;s2、top=s2、base;return ;}//除数不为0
ﻩelse a=a/b;break;
default :error=1;
ﻩ}
ﻩfprintf(file,"%lf %c %lf= %lf\n",*(s1、top—1),*(s2、top-1),b,a);
ﻩ*(s1、top—1)=a; //将运算结果入栈
ﻩs2、top--; //运算符退栈
ﻩreturn ;
}
void qiuzhi(char *cr)
// qiuzhi();该函数完成对表达式得处理
{
int i=0,k,h,flag,fuhao=0;
double sum,j;
ﻩs1、base=s1、top=shuzhi;
s2、base=s2、top=fuha; //数字栈与符号栈初始化
*(s2、top)=’#'; //将'#’入栈,方便循环
ﻩs2、top++;
ﻩwhile(s2、top!=s2、base)
ﻩ{
ﻩ sum=0;
ﻩ flag=0;
ﻩk=10;j=1;h=1;ﻩ
ﻩwhile(cr[i]>='0’&&cr[i]<='9’||cr[i]=='、')
ﻩﻩﻩ//若当前得字符就是数字,就将char型得数据转换为double型
ﻩ {
ﻩﻩ if(cr[i]==’、')
ﻩ{
ﻩﻩif(cr[i—1]〈’0'||cr[i-1]>'9’||i==0||cr[i+1]<'0’||cr[i+1]>'9')
//判断小数点就是否出错
ﻩﻩ ﻩ{error=1;break;}
ﻩ ﻩelse
ﻩ {k=1;h=10;}
}
ﻩ else
ﻩﻩﻩ{
ﻩ ﻩ flag=1;j=j*h;
sum=sum*k+(cr[i]-48)/j;
ﻩ }
i++;
}
ﻩ if(flag) //flag不为0表明有数据需要入栈
ﻩ{ﻩ
ﻩﻩif(fuhao){sum=-sum;fuhao=0;}
//fuhao就是个标志记号,值不为0表明刚才转换得值为负数
ﻩﻩ*(s1、top)=sum;
ﻩﻩs1、top++;
ﻩ}
else
{
ﻩswitch(cr[i])
ﻩﻩ {
ﻩﻩﻩcase '-’:if(cr[i-1]==’('||i==0){fuhao=1;i++;break;}
ﻩ //判断就是不就是负号,若不就是则进行与加号相同得操作
ﻩ ﻩ//当’-'出现在表达式第一位或就是'('后第一位,则应将其判为负号
ﻩﻩcase '+':
ﻩﻩﻩﻩ//加、减号得优先级只比'('与'='高,若栈顶元素为这两者之一
ﻩﻩ ﻩ//就将其入栈,否则执行运算操作
ﻩ ﻩif(*(s2、top—1)=='('||*(s2、top—1)==’#’)
ﻩﻩﻩﻩ{
ﻩﻩ ﻩ*(s2、top)=cr[i];
ﻩ ﻩ s2、top++;
ﻩ ﻩi++;
ﻩﻩﻩ}
ﻩﻩﻩ else jisuan();break;
ﻩ ﻩcase ’*':
ﻩﻩ case '/':
ﻩ ﻩﻩ//乘、除号得优先级只比'*'、’/'与’^'低,若栈顶元素为这三者之一
ﻩﻩﻩ//就执行运算操作,否则将其入栈
ﻩif(*(s2、top—1)=='*'||*(s2、top—1)=='/’)jisuan();
ﻩﻩ else
ﻩﻩ {
ﻩﻩﻩ *(s2、top)=cr[i];
ﻩs2、top++;
ﻩ ﻩi++;
ﻩﻩ }break;
ﻩﻩﻩcase '(’: *(s2、top)=cr[i]; s2、top++;i++;break;
ﻩﻩﻩﻩ//未入栈时'('得优先级最高,所以它一定要入栈
ﻩ //但一入栈其优先级就应降为最低
ﻩﻩ case ’)':
ﻩﻩ ﻩ//注意:由于'()'运算优先级最高故我直接进行运算,
ﻩﻩ //直到栈顶元素为’(’后将’(’出栈,故符号栈中一定没有')’,
ﻩﻩ ﻩ//这也就是我进行以上优先级判断得前提
ﻩ ﻩif(*(s2、top—1)==’(')
ﻩﻩﻩ {
ﻩﻩ ﻩ s2、top—-;
ﻩ i++;
ﻩ }
ﻩelse jisuan();break;
ﻩcase ’=':
ﻩ ﻩﻩ//表达式结束,若符号栈栈顶元素不为'#',进行运算
ﻩ//否则退栈,结束
ﻩﻩﻩ if(*(s2、top—1)==’#')
ﻩﻩﻩﻩ{
ﻩ ﻩs2、top--;
ﻩ }
ﻩﻩﻩ else jisuan();break;
ﻩ default :i++; //清除空格及未定义符号
ﻩ ﻩ}
ﻩ}
if(error)break;
ﻩ}
if(error||s1、top-1!=s1、base)
ﻩ //若运行出错或就是数字栈中得元素不就是一个,就进行出错提醒
{
if(error==2)
ﻩ{
ﻩﻩ printf("除数不能为0!\n");
ﻩﻩ fprintf(file,"%s\n”,"除数不能为0!”);
ﻩ }
ﻩ else
ﻩ{
ﻩ printf("表达式错误!\n");
fprintf(file,"%s\n","表达式错误!");
ﻩ }
}
ﻩelse
ﻩﻩ//结果输出,输出小数点后六位,
{
fprintf(file,”结束\n");
printf("%、6lf\n",*(s1、base));
ﻩﻩfprintf(file,"%、6lf\n",*(s1、base));
ﻩ}
ﻩreturn ;
}
void main()
{
char cr[60];
char c=’a’;
(outfile,"w+");
ﻩ//使用提示
printf("*******************************************************************************\n");
ﻩprintf("*********************************李斐计算器************************************\n");
ﻩprintf(”四则简易计算器\n\n");
printf("输入表达式例如 2+4= \n\n");
printf(”最后按 # 键 则会退出保存\n\n");
ﻩprintf("谢谢使用\n\n");
printf("------—---—————-----——----—-----—-——-—-——--—------—---———-—-----——-———--—--——-\n”);
ﻩprintf("******************************************************************************\n");
ﻩ//循环输入表达式,按'#'键退出
while(c!=’#')
{
ﻩ error=0;
printf("输入表达式:\n");
ﻩﻩgets(cr);
fprintf(file,"表达式:%s\n",cr);
qiuzhi(cr);
printf("任意键继续,按 # 键退出:\n”);
ﻩc=getch();
}
fclose(file);
}
展开阅读全文