数据结构课程设计用栈求表达式.docx
- 文档编号:28328431
- 上传时间:2023-07-10
- 格式:DOCX
- 页数:28
- 大小:80.59KB
数据结构课程设计用栈求表达式.docx
《数据结构课程设计用栈求表达式.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计用栈求表达式.docx(28页珍藏版)》请在冰豆网上搜索。
数据结构课程设计用栈求表达式
课程设计报告
学院、系:
吉林大学珠海学院计算机科学与技术系专业:
班级:
课程设计科目
学生姓名:
指导教师:
完成时间:
网络工程十三班数据结构林艾鑫余江2010年10月-12月
题目十三、利用栈求表达式的值
一、设计任务与目标
编写程序实现表达式求值,即验证某算术表达式的正确性,若正确,则计算该算术表达式的值。
主要功能描述如下:
1、从键盘上输入表达式,以“=”号结束表达式。
2、分析该表达式是否合法:
(1)是数字,则判断该数字的合法性。
若合法,则压入数据到堆栈中。
(2)是规定的运算符,则根据规则进行处理。
在处理过程中,将计算该表达式的值。
(3)若是其它字符,则返回错误信息。
3、若上述处理过程中没有发现错误,则认为该表达式合法,并打印处理结果。
附加功能:
1.规定表达式的合法性
2.小数计算
3.计算记录的保存与查看
4.
(1)规定表达式的合法性,括号配对,不能出现“6++3”、“6+-3”等符号重叠的情况。
(2)表达式开头只能是数字或“(”,表达式中只能有一个“=”。
程序中应主要包含下面几个功能函数:
voidinitstack():
初始化堆栈
intmake_str():
语法检查并计算
intpush_num(doublenum):
将操作数压入堆栈
charprocede(chartop,charcode):
处理操作码
intchange_opnd(intoperate):
将字符型操作码转换成优先级
intchange_opnd(charcode):
将操作码压入堆栈
charpop_opnd(opnd*op):
将操作码弹出堆栈
intcaculate(intcur_opnd):
简单计算+,-,*,/
doublepop_num(num*nu):
弹出操作数
二、方案设计与论证
1.定义一个expression全局表达式结构体expr[1000]存放计算过的表达式
(expstr[MAXSIZE])和计算结果(result)、一个计量器(i)、一个表达式字符串、一个操作码栈和一个操作数栈;
2.
3.
4.
5.把表达式字符串从头到尾逐一扫描,将输入的表达式进行语法检查;第一个字符只能是数字或“(”,最重一个字符只能是“=”;表达式括号必须配对,中间不能出现“=”;在“(”前面只能是“+、-、*、/、(”,在“+、-、*、/、=、)”前面
只能是数字或“)”;
6.把表达式字符串从头到尾逐一扫描,直到表达式扫描完毕,操作码栈为
空;
7.
8.
9.把字符根据运算优先级别选择操作;把表达式中的数值部分字符串转成数值压入操作数栈;是“(”直接压入到操作码栈,级别比操作码栈顶元素高的,把运算符压
入操作码栈;
10.级别比操作码栈低的,弹出操作码栈的栈顶元素和操作数栈的两个栈顶
元素,进行运算后再压入操作数栈;
11.是“)”,若操作码栈顶是“(”,把弹出操作码栈顶元素,否则“)”视为
级别最低的元素,重复7;
12.最后计算出结果并将其存放在expr[i],计量器加1;
13.重复计算后,将结果保存在文件里,并统计计算次数;
14.查看多次计算结果,以表形式输出;
15.查看本次计算记录,以表形式输出;
16.清除计算记录,重新计算。
三、算法说明
(一)程序总共有如下函数:
主要函数:
voidstart(opnd*op,num*nu)//程序主菜单
voidstart2(opnd*op,num*nu)//第二层计算选择,子菜单
voidload()//显示所有计算记录
voidsave()//保存计算结果
voidcheck()//显示本次计算结果
voidresult(opnd*op,num*nu)//计算结果
doublecaculate(opnd*op,num*nu)//简单计算+,-,*,/
表达式处理函数:
intmake_str()//语法检查
doublechange_num(charstr[])//数字字符串转成double型数字
charprocede(chartop,charcode)//处理操作码,判断栈的操作
intchange_opnd(charcode)//字符型操作码转换优先级,非表达式字符返回-2栈操作函数:
doubleget_num(num*nu)//查看操作数栈栈顶
doublepop_num(num*nu)//操作数栈出栈
intpush_num(num*nu,doubleda)//压入操作数栈
intempty_num(num*nu)//判空
voidinitstack(num*nu)
charget_opnd(opnd*op)//查看栈顶
charpop_opnd(opnd*op)//出栈
intpush_opnd(opnd*op,charco)//压栈
intempty_opnd(opnd*op)//判空
voidinitstack(opnd*op)//初始化栈
(二)函数间的调用关系:
●main():
主函数→start();
↗load()→start();
●start()程序模式函数→清空文件→exit();
↘make_str()→result(op,nu)→start2()→start();
↗load→start();
●start2()子菜单→save()→start2();
↘check()→start2();
●result(op,nu)计算结果→initstack(op)→initstack(nu)→push_opnd(op,'=')→
↗push_num(nu,change_num(str2));
→change_opnd(*ps)↗push_opnd(op,*ps);
↘procede(get_opnd(op),*ps)→pop_opnd(op);
↘push_num(nu,caculate(op,nu))●caculate(op,nu)→b=pop_num(nu)→a=pop_num(nu)→pop_opnd(op)
✓main()函数:
调用了一个函数start(),start()判断执行查看所有计算记录
函数load(),或是清空以往的所有计算记录,或是退出程序,或是检查输入表达式语法make_str()并计算表达式result(op,nu)的操作。
✓result(op,nu)函数:
是计算表达式,调用了初始化栈函数和字符级别判断
change_opnd(*ps),若是数字,则调用转化数字change_num(str2)然后压入操作数栈,若是运算符,刚调用判断操作procede(get_opnd(op),*ps),若是“<”,则压入操作码栈push_opnd(op,*ps),若是“=”,则弹出操作码栈顶pop_opnd(op),若是“>”,则弹出操作码栈的栈顶元素和操作数
栈的两个栈顶元素,进行运算caculate(op,nu)后再压入操作数栈,计算完毕后按start()顺序运行。
start2()函数:
在计算结果后调用跟随的选择菜单,进行查看结果check()、
保存结果save()、查看计算记录load()、回到主菜单的操作。
(三)流程图:
四、全部源程序清单
#include
#include
#include
#include
#defineMAXSIZE100
#defineN1000
inti=0;
//
表达式数
structexpression//
表达式结构
{
longdoubleresult;
charexpstr[MAXSIZE];
}expr[N];//
表达式的一个整体容器s
typedefstruct//操作码栈定义
{
charcode[MAXSIZE];
inttop;
}opnd;
typedefstruct//操作数栈定义
{
doubledate[MAXSIZE];
inttop;
}num;
//《——opnd栈操作——》:
voidinitstack(opnd*op)//初始化栈
{
op->top=-1;
}
intempty_opnd(opnd*op)//判空
{
if(op->top==-1)
return0;
elsereturn1;
}
intpush_opnd(opnd*op,charco)//压栈
{
if(op->top==MAXSIZE-1)
{
printf("The\"opnd\"stackisfull.");return0;
}
op->top++;
op->code[op->top]=co;
return1;
}
charpop_opnd(opnd*op)//出栈
{
chara='\0';
if(op->top==-1)
{
printf("error:
The\"opnd\"stackisempty.");returna;
}
a=op->code[op->top];
op->top--;
returna;
}
charget_opnd(opnd*op)//查看栈顶
{
chara='\0';
if(op->top==-1)
{
printf("error:
The\"opnd\"stackisempty.");returna;
}
else
returnop->code[op->top];
}
//《——num栈操作——》:
voidinitstack(num*nu)
{
nu->top=-1;
}
intempty_num(num*nu)//判空
{
if(nu->top==-1)
return0;
elsereturn1;
}
intpush_num(num*nu,doubleda)//压栈
{
if(nu->top==MAXSIZE-1)
{
printf("error:
The\"date\"stackisfull.");return0;
}
nu->top++;
nu->date[nu->top]=da;
return1;
}
doublepop_num(num*nu)//出栈
{
doublea='\0';
if(nu->top==-1)
{
printf("error:
The\"date\"stackisempty.");
returna;
}
a=nu->date[nu->top];
nu->top--;
returna;
}
doubleget_num(num*nu)//查看栈顶
{
if(nu->top!
=-1)
returnnu->date[nu->top];
}
//《——结束栈定义操作——》
//《——函数操作——》:
intchange_opnd(charcode)//将字符型操作码转换成优先级,非表达式字符反回-2
{
switch(code)
{
case'=':
return1;break;
case')':
return2;break;
case'+':
return3;break;
case'-':
return3;break;
case'*':
return4;break;
case'/':
return4;break;
case'(':
return0;break;//操作码级别>=0;case'1':
case'2':
case'3':
case'4':
case'5':
case'6':
case'7':
case'8':
case'9':
case'0':
case'.':
return-1;//操作数级别=-1;
default:
return-2;//其它符号级别=-2}
}
charprocede(chartop,charcode)//处理操作码,判断栈的操作
{
if(change_opnd(code)==0)//“(”入栈
return('<');
else
if(change_opnd(code)==2&&change_opnd(top)==0)//“(”和“)”同时
出现,“(”出栈,“)”不入栈
return('=');
else
if(change_opnd(code)<=change_opnd(top))//弹出两个数字和一个符号进行计算
return('>');
else
return('<');//入栈
}
doublechange_num(charstr[])//数字字符串转成double型数字
{
char*s=str;
intp=1,q=0;//p=小数点前位数,q=小数点后位数
chard[]=".",z[]="0";
doubleda=0;
if(strstr(str,d)==0)//判断是否有小数点
p=strlen(str);
else
if(strstr(str,d)==str)//没有输入小数点前的数,如“.032”{
p=1;
q=strlen(str)-1;
strcpy(str,strcat(z,str));
}
else
{
p=strstr(str,d)-str;
q=strlen(str)-p-1;
}
for(inti=0;i
123=1*100+2*10+3*1
da=da+((int)str[i]-48)*pow(10,p-i-1);
for(intj=0;j 0.123=1*0.1+2*0.01+3*0.001 da=da+((int)str[strlen(str)-1-j]-48)*pow(0.1,q-j);returnda; } intmake_str()//语法检查 { char*p,*p1; intn=0; printf("\n请输入表达式,以“=”结尾: "); gets(expr[i].expstr); p=expr[i].expstr; p1=p; while (1) { if(*p=='\0') if(*(p-1)=='=')//语法检查结束 break; else {//没有以"="结尾 printf("\n表达式以\"=\"结尾。 请重新输入: "); gets(expr[i].expstr); p=expr[i].expstr; n=0; continue; } if(change_opnd(*p)==2)//一个")",n-1 n--; if(change_opnd(*p)==0)//一个"(",n+1 n++; if(*p1==*p)//第一个字符的判断,只能以“数字”或“(”开头,不能有非法字符 if(change_opnd(*p)>0) { printf("\n表达式只能以“数字”或“(”开头。 请重新输入: "); gets(expr[i].expstr); p=expr[i].expstr; n=0; continue; } else if(change_opnd(*p)==-2) { printf("\n表达式\"%c\"为非法字符。 请重新输入: ",*p);gets(expr[i].expstr); p=expr[i].expstr; n=0; continue; } else {//合法刚跳到下一个字符 p=p+1; continue; } if(change_opnd(*p)==-2)//非法字符判断 { printf("\n表达式\"%c\"为非法字符。 请重新输入: ",*p);gets(expr[i].expstr); p=expr[i].expstr; n=0; continue; } if(change_opnd(*p)==0)//"("前一个字符只能是"+、-、*、/、("{ if(change_opnd(*(p-1))<3&&change_opnd(*(p-1))>4)if(change_opnd(*(p-1))! =0) { printf("\n表达式\"%c\"或\"%c\"不符合语法。 请重新输入: ",*(p-1),*p); gets(expr[i].expstr); p=expr[i].expstr; n=0; continue; } } if(change_opnd(*p)>0)//"+、-、*、/、=、)"前一个字符只能是数字和")" if(change_opnd(*(p-1))! =-1) if(change_opnd(*(p-1))! =2) { printf("\n表达式\"%c\"或\"%c\"不符合语法。 请重新输入: ",*(p-1),*p); gets(expr[i].expstr); p=expr[i].expstr; n=0; continue; } if(change_opnd(*p)==1)//判断表达式中是否有"="重复出现,最后括号是否配对 { if(*(p+1)! ='\0') { printf("\n表达式中\"=\",只能出现在表达式结束处。 请重新输入: "); gets(expr[i].expstr); p=expr[i].expstr; n=0; continue; } if(n! =0) { printf("\n表达式括号不配。 请重新输入: ");gets(expr[i].expstr); p=expr[i].expstr; n=0; continue; } } p=p+1; } return1; } doublecaculate(opnd*op,num*nu)//简单计算+,-,*,/ { doubleb=pop_num(nu),a=pop_num(nu); switch(pop_opnd(op)) { case'+': return(a+b);break; case'-': return(a-b);break; case'*': return(a*b);break; case'/': return(a/b);break; } } voidresult(opnd*op,num*nu)//计算结果 { charstr2[MAXSIZE]="",str3[2]="0"; char*ps=expr[i].expstr; initstack(op);//初始化栈 initstack(nu); push_opnd(op,'='); while(! ((*ps=='=')&&(get_opnd(op)=='=')))//检查是表达式和操作码是否到尾 if(change_opnd(*ps)==-1)//操作数处理 { while(change_opnd(*ps)==-1) { strncpy(str3,ps,1);//数字字符一个个取出放在str2strcat(str2,str3); ps++; } push_num(nu,change_num(str2)); strcpy(str2,""); } else//操作码处理 { switch(procede(get_opnd(op),*ps)) { case'<': push_opnd(op,*ps);break; case'=': pop_opnd(op);break; case'>': push_num(nu,caculate(op,nu));continue;break;} if(*ps==')'&&get_opnd(op)=='=') { ps++; continue; } if(*ps=='='||get_opnd(op)=='=') continue;//表达式和操作码有一个到尾,则跳出继续循环 ps++; } expr[i].result=get_num(nu); printf("\n\t表达式: %s\t计算结果: %lf\n",expr[i].expstr,expr[i].result); printf("\t----------------------------------------------------------------\n"); i++;//表达式个数加1; } voidcheck()//显示计算结果 { for(intn=0;n { printf("\n"); printf("\t%d --------------------------------------------------------------\n",n+1); printf("\t表达式: %s",expr[n].expstr); printf("\t计算结果: %.2lf\n",expr[n].result); if(expr[n].expstr[0]=='#')break;//只显示当次计算的记录} printf("\t----------------------------------------------------------------\n"); } voidsave()//保存计算结果 { FILE*fp; intm,n; if((fp=fopen("calculate.dat","ab"))==NULL)//创建文件 { printf("cannotopenfile\n"); return; } if(expr[i-1].expstr[0]=='#')//不能重复保存 { printf("*提醒: 记录已保存过,不需要再次保存。 \n"); return; } for(n=i;n>0;n--)//记录最后一个#号位置,即未保存的结果的开始位置,重复保存只会追加 if(expr[n-1].expstr[0]=='#') break; strcpy(expr[i].expstr,"#表达式个数: ");//每次保存都统计计算次数expr[i].result=i-n; i++; for(m=n;m if(fwrite(&expr[m],sizeof(structexpression),1,fp)! =1)//将表达式和计算结果存到文件中 printf("filewriteerror\n"); fclose(fp); printf("*提醒: 计算记录已经保存\n"); } voidload()//显示所有计算记录 { intm; expressione[N]; FILE*fp
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 课程设计 用栈求 表达式