湖南大学数据结构四则运算表达式报告Word文档下载推荐.docx
《湖南大学数据结构四则运算表达式报告Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《湖南大学数据结构四则运算表达式报告Word文档下载推荐.docx(13页珍藏版)》请在冰豆网上搜索。
课程实习报告
题目:
四则运算表达式求值
学生姓名
学生学号
专业班级
指导老师李晓鸿
完成日期
一、需求分析
1.本程序要求首先输入一组数据进行四则运算,输入的数据是按照中缀表达式的结构输入的,完成初始化后,把中缀表达式转化为后缀表达式(逆波兰表达式)输出,同时输出计算结果。
输入举例:
21+23*(12-6)//正常的中缀表达式结构输入有数据,有+-*/()
21+(12-6)*23
25^12*1+2
2577//数据输入中不能留空格,两个数据中间必须是符合四则运算的数据(+-*/())
2.程序的功能将输入的中缀表达式转化为后缀表达式输出,同时输出计算结果;
3.程序的输出就是转化后的后缀表达式以及计算的结果,输出结果间用空格隔开;
输出举例:
接上
后缀表达式为:
2123126-*+//输出结果间用一个空格隔开
计算结果为:
159
21126-23*+
输入非法,程序结束!
4.测试数据:
见上。
二、概要设计
抽象数据类型
中缀表达式的存入和读取是核心问题,计算只要用到两个临时的栈一个存操作数,一个存运算符。
利用二叉树,根节点存操作符,其他节点存操作数,利用二叉树的遍历可以方便的存入和读出操作数和运算符。
(后序遍历实现后缀表达式)二叉树的ADT与节点的ADT分开定义
ADTBinNode
数据对象:
整数
数据关系:
无
基本操作:
intval()//返回结点的数值
VoidsetVal(constElem&
)//设置节点的值
inlineBinNode*left()const//获取左结点
inlineBinNode*right()const//获取右结点
voidsetLeft(Node*it)//设置左结点
voidsetRight(Node*it)//设置右结点
BoolisLeaf()//是叶子节点吗?
二叉树
ADTBinTree
BinNode
BinTree(charexp[]);
//利用字符串建树
voidpostOrderTraverse(Bintree*T,visit());
//后序遍历
ADTStack
BinNode类型
线性关系
boolpush(constBinNode&
item);
boolpop(BinNode&
it);
booltopValue(BinNode&
intlength();
const
算法的基本思想
初始化:
怎样把中缀表达式转为二叉树?
(1)输入表达式;
(2)对表达式做括号检测;
(3)利用栈的思想转化中缀表达式,最后得到完整二叉树;
提取表达式输出及计算:
利用后序遍历完成从二叉树中提取后缀表达式,按照逆波兰表达式计算过程,遇到操作数压栈,遇到操作符,栈中弹出两个操作数,做运算,结果压入栈,知道只剩下一个数据为止。
程序的流程
程序由四个模块组成:
(1)初始化模块:
完成中缀表达式的输入;
(2)转换建树模块:
中缀表达式建树,并利用后序遍历输出树。
(3)计算模块:
利用后缀表达式计算表达式;
(4)输出模块:
输出后缀表达式及计算结果。
三、详细设计
物理数据类型
算法的具体步骤
伪代码:
输入和括号粗略匹配:
while(i<
100)
{
cin.get(c);
//输入字符,可读入/n
ch[i++]=c;
if(c=='
\n'
){
ch[--i]='
#'
;
break;
}//endif
}
i=0;
while(ch[i]!
='
)
if(ch[i]=='
('
&
ch[i+1]!
)'
coutk++;
elseif(ch[i]=='
ch[i+1]=='
{
coutk=1;
}
ch[i-1]!
coutk--;
i++;
if(coutk<
0||coutk>
0)
cout<
<
"
括号不匹配!
endl;
exit(0);
建树:
算法利用两个临时的栈,一个存操作数,一个存操作符,检测到操作数,建立叶子节点,压入存入操作数栈,遇到操作符,存入操作符栈,每次存操作符时与前一个操作符做运算级别比较,若上一个操作符级别大,则弹出上一个操作符,同时弹出两个操作数建立二叉树,操作符做根节点,在把根节点压入操作数栈,括号做优先级最高处理,遇到右括号(前提是有了左括号和必要的运算式),操作符栈弹出,同时弹出两个操作数,建立二叉树,根节点压入操作数的栈。
BinTree:
:
BinTree(charexp[])//根据字符串exp的内容构建表达式树T
{
stack<
BinNode*>
PTR;
//存放表达式树中的节点指针
char>
OPTR;
//存放操作符
charop;
inti=0;
OPTR.push('
);
op=OPTR.top();
boolflag=true;
while(!
((exp[i]=='
)&
(OPTR.top()=='
)))
if(isdigit(exp[i]))
flag=true;
i+=CrtLeafNode(PTR,&
exp[i]);
//操作数,建立叶子节点并入栈PTR
elseif(exp[i]=='
'
i++;
else
switch(exp[i])
{
case'
{
flag=true;
OPTR.push(exp[i]);
i++;
break;
}
op=OPTR.top();
OPTR.pop();
while(op!
{
flag=true;
CrtSubTree(PTR,op);
//操作数栈建立分支节点
op=OPTR.top();
}//endwhile
break;
default:
//exp[i]是+-*/
while(!
OPTR.empty())
{
if(!
flag)
cout<
不能有连续的两个运算符!
exit(0);
}
if(Precede(op,exp[i])=='
>
'
)//操作符比较优先级
OPTR.pop();
if(exp[i]!
OPTR.push(exp[i]);
i++;
flag=false;
}
}
root=PTR.top();
//返回树的根节点
PTR.pop();
}
后序遍历:
voidpostorder(BinNode*subroot,char*exp,int&
count)
if(subroot!
=NULL)
postorder(subroot->
left(),exp,count);
right(),exp,count);
for(inti=0;
i<
subroot->
length();
i++)
exp[count++]=subroot->
setVal(i);
exp[count++]='
};
最后输出exp这个字符串,就是逆波兰表达式。
计算:
按照存在字符串中的后缀表达式,遇到数字转换为double实数,压入栈,遇到操作符,栈中弹出两元素,同时做运算(/除数不能问0),结果压入栈,知道剩下最后一个数字为止;
voidevaluate(charch[],double&
result)
SqStackS;
//运算栈
inti;
if(isdigit(ch[i]))
{
i+=EvalValue(&
ch[i],S);
//转换实数,压栈;
EvalExpr(ch[i],S);
//弹栈,做相应的运算;
if(S.length()==1)
result=S.pop();
result为最后的结果
intEvalValue(char*ch,SqStack&
S)
{
doubleresult=0;
chara;
a=ch[i];
while(isdigit(a))
{
result=10*result+(double)(a-48);
a=ch[++i];
S.push(result);
returni;
voidEvalExpr(charch,SqStack&
doubles1=0;
doubles2=0;
if(S.length()<
2)
printf("
\n表达式错误\n"
switch(ch)
case'
+'
s1=S.pop();
s2=S.pop();
S.push(s2+s1);
-'
S.push(s2-s1);
*'
S.push(s2*s1);
/'
if(s1!
=0)
S.push(s2/s1);
cout<
除数不能为0!
无结果!
default:
printf("
error"
算法的时空分析
此算法利用栈和二叉树来实现,故次算法的的时间复杂度为O(N)
输入和输出的格式
输入
本程序可以将输入的中缀表达式转化为后缀表达式,并输出计算结果
请输入表达式。
回车表示结束
输出
逆波兰表达式为为:
表达式值为:
4、测试结果
5、实验心得
四则运算表达式存入栈中,考虑到的情况十分的复杂,运算符的优先级和括号的问题,还有各种意外情况的处理,括号的匹配,十分麻烦,不愧是做的最复杂的实验;
6、附录
EX_4.cpp