i-1,a
i>|a
i-1,a
i∈D,i=2,„,n}
基本操作:
InitStack(&S)
操作结果:
构造一个空栈S。
GetTop(S,&e)
初始条件:
栈S已存在。
操作结果:
若栈S不空,则以e返回栈顶元素。
Push(&S,e)
初始条件:
栈S已存在。
操作结果:
在栈S的栈顶插入新的栈顶元素e。
Pop(&S,&e)
初始条件:
栈S已存在。
操作结果:
删除S的栈顶元素,用e返回其值。
}ADTStack
2.设定运算表达式的抽象数据类型为:
ADTEvaluateExpression{
数据对象:
D={a
i|a
i为数字及运算符,i=1,2,„,n,n≥0}
数据关系:
R1={}
基本操作:
Precede(a1,a2)
初始条件:
字符a1,a2存在。
操作结果:
判定运算符的优先级
In(d)
初始条件:
字符d存在。
操作结果:
判断c是否为七种运算符之一
Operate(a,theta,b)
初始条件:
字符a,theta,b存在。
操作结果:
运算表达式结果。
}ADTEvaluateExpression
3.本程序包含3个模块:
(1)主程序模块:
intmain()
{
初始化;
do{
接受命令:
处理命令:
}
return0;
}
(2)栈模块——实现栈抽象数据类型
(3)求解算术表达式模块——实现算术表达式数据类型
各模块之间的调用关系如下:
主程序模块
↓
↓
栈模块
求解算术表达式模块
三、详细设计
1.数据类型、字符类型。
typedefdoubleSElemType;//数据类型
charPrecede(chara1,chara2)
{
charr;//字符类型
}
2.栈类型
typedefstructSqStack{
SElemType*base;
SElemType*top;
intstacksize;
}SqStack;
栈的基本操作设置如下:
voidInitStack(SqStack&S)//构造一个空栈
boolGetTop(SqStackS,SElemType&e)//若栈不空,则用e返回S的栈顶元素,并返回true;否则返回false
boolPush(SqStack&S,SElemTypee)//插入元素为e的新的栈顶元素boolPop(SqStack&S,SElemType&e)//若栈不空,则删除S的栈顶元素,用e返回其值
其中部分操作的算法:
boolPush(SqStack&S,SElemTypee)
{//插入元素为e的新的栈顶元素
if(S.top-S.base>=S.stacksize)
{//栈满,追加存储空间
S.base=(SElemType*)realloc(S.base,(S.stacksize+STACKINCREMENT)*sizeof(SElemType));
if(!
S.base)
exit(-1);//存储空间分配失败
S.top=S.base+S.stacksize;
S.stacksize+=STACKINCREMENT;
}
*S.top++=e;//top自增
returntrue;
}
boolPop(SqStack&S,SElemType&e)//若栈不空,则删除S的栈顶元素,用e返回其值
{
if(S.top==S.base)
returnfalse;
e=*--S.top;//删除一个元素,top减一
returntrue;
}
3.求解算术表达式的伪算法
SElemTypeEvaluateExpression(){
SqStackOPTR,OPND;//OPTR和OPND分别为运算符栈和运算数栈charc;
charData[20];//定义此数组为了存放整数或小数
SElemTypea,b,d,e;
InitStack(OPTR);//构造一个运算符栈
InitStack(OPND);//构造一个运算数栈
Push(OPTR,'\n');//将换行符压入栈底
c=getchar();
GetTop(OPTR,e);
while(c!
='\n'||e!
='\n')//栈顶不是换行符且输入不是换行符
{
if(In(c))//是符号则进栈
{
switch(Precede(e,c))
{
case'<':
//栈顶元素优先级低
Push(OPTR,c);
c=getchar();
break;
case'=':
//脱括号并接受下一字符
Pop(OPTR,e);
c=getchar();
break;
case'>':
//退栈并将运算结果入栈
Pop(OPTR,e);
Pop(OPND,b);
Pop(OPND,a);
Push(OPND,Operate(a,e,b));
break;
}
}
elseif(c>='0'&&c<='9'||c=='.')
{
Push(OPND,c-48);
c=getchar();
}
else
{
cout<<"error!
输入错误!
"<exit(-1);
}
GetTop(OPTR,e);
}
GetTop(OPND,e);
returne;
}
4.主函数和其他函数的伪算法
intmain()//主程序
{
SElemTyperesult;//初始定义
cout<<"请输入表达式"<result=EvaluateExpression();//执行函数操作命令
cout<<"结果为:
"<return0;
}
charPrecede(chara1,chara2)//判定运算符的优先级函数。
{
charr;
switch(a2)
{
case'+':
case'-':
//加减运算优先级相同
if(a1=='('||a1=='\n')
r='<';
else
r='>';
break;
case'*':
case'/':
//乘除运算优先级相同
if(a1=='*'||a1=='/'||a1==')')
r='>';
else
r='<';
break;
case'(':
if(a1==')')
{
cout<<"括号匹配错误!
"<exit(-1);
}
else
r='<';
break;
case')':
if(a1=='(')
r='=';
elseif(a1=='\n')
{
cout<<"error!
没有左括号"<exit(-1);
}
else
r='>';
break;
case'\n':
switch(a1)
{
case'\n':
r='=';
break;
case'(':
cout<<"error!
没有右括号"<exit(-1);
default:
r='>';
}
break;
}
returnr;
}
boolIn(chard)//判断c是否为七种运算符之一的函数
{
switch(d)
{
case'+':
case'-':
case'*':
case'/':
case'(':
case')':
case'\n':
returntrue;
default:
returnfalse;
}
}
5.函数的调用关系图反映了演示程序的结构层次:
主程序
↓————————↓————————↓
InitializationReadCommandInterpret
↓
↓————————————————↓
InitEvaluateExpressionPrintEvaluateExpression↓
↓————————↓——————↓——————↓
InitStackPushPopGetTop
四、调试分析
1.这次作业思路比较简单,核心问题就是表达式的运算,要区分运算符的优先顺序。
通过运用栈后进先出的特点实现算法功能,调用push和pop等函数,实现一系列操作。
2.调试过程中,起初想打换行符时打成了’\’,忘了打字母n,结果程序调试总是有错误,改成’\n’后便成功运行了,可见,细节之处也很重要。
3.运用了很多的栈的基本操作,让我对栈的内容熟悉了不少,收获很大。
4.本题中时间复杂度为O(n)
五、用户手册
本程序的运行环境为DOS操作系统,执行文件为:
EvaluateExpression.exe。
六、测试结果
(1)请输入表达式:
3*(7-2);
结果为:
15
(2)请输入表达式:
8;
结果为:
8
(3)请输入表达式:
1+2+3+4;
结果为:
10
(4)请输入表达式:
88-1*5;
结果为:
82
(5)请输入表达式:
1024*4/8;
结果为:
512
(6)请输入表达式:
(20+2)*(6/2);
结果为:
6
(7)请输入表达式:
3-3-3;
结果为:
-3
(8)请输入表达式:
8/(9-9);
结果为:
error!
除数不能为零
(9)请输入表达式:
2*(6+2*(3+6*(6+6)));
结果为:
312
(10)请输入表达式:
(((6+6)*6+3)*2+6)*2;
结果为:
312
七、附录
源代码见“源程序文档”