湖南大学数据结构四则运算表达式报告.docx
《湖南大学数据结构四则运算表达式报告.docx》由会员分享,可在线阅读,更多相关《湖南大学数据结构四则运算表达式报告.docx(13页珍藏版)》请在冰豆网上搜索。
湖南大学数据结构四则运算表达式报告
实验4四则运算表达式求值
背景
在工资管理软件中,不可避免的要用到公式的定义及求值等问题。
对于数学表达式的计算,虽然可以直接对表达式进行扫描并按照优先级逐步计算,但也可以将中缀表达式转换为逆波兰表达式,这样更容易处理。
问题描述
四则运算表达式求值,将四则运算表达式用中缀表达式,然后转换为后缀表达式,并计算结果。
基本要求
(1)使用二叉树来实现。
实现提示
利用二叉树后序遍历来实现表达式的转换,同时可以使用栈来求解后缀表达式的值。
输入输出格式:
输入:
在字符界面上输入一个中缀表达式,回车表示结束。
输出:
如果该中缀表达式正确,那么在字符界面上输出其后缀表达式和计算结果,其中后缀表达式中两相邻操作数之间利用空格隔开;如果不正确,在字符界面上输出表达式错误提示。
选作内容
(1)在输入输出方式上要求使用:
输入:
将中缀表达式存于文本文件中,程序从该文本文件中读出表达式。
输出:
如果该中缀表达式正确,则将后缀表达式输出到该文件中原表达式的后面,它们之间用“---”后相连;如果不正确,请在输出表达式错误提示到该文件原表达式的后面,它们之间用“---”相连。
(2)利用堆栈来实现中缀表达式转换为后缀表达式。
测试用例
输入:
21+23*(12-6)
输出:
2123126-*+
resultis159
课后习题
采用非递归的编程方法分别统计二叉树的节点个数度为1和叶子节点的个数以及数据值的最大值和最小值。
实验预习报告部分
HUNANUNIVERSITY
课程实习报告
题目:
四则运算表达式求值
学生姓名
学生学号
专业班级
指导老师李晓鸿
完成日期
一、需求分析
1.本程序要求首先输入一组数据进行四则运算,输入的数据是按照中缀表达式的结构输入的,完成初始化后,把中缀表达式转化为后缀表达式(逆波兰表达式)输出,同时输出计算结果。
输入举例:
21+23*(12-6)//正常的中缀表达式结构输入有数据,有+-*/()
21+(12-6)*23
25^12*1+2
2577//数据输入中不能留空格,两个数据中间必须是符合四则运算的数据(+-*/())
2.程序的功能将输入的中缀表达式转化为后缀表达式输出,同时输出计算结果;
3.程序的输出就是转化后的后缀表达式以及计算的结果,输出结果间用空格隔开;
输出举例:
接上
后缀表达式为:
2123126-*+//输出结果间用一个空格隔开
计算结果为:
159
后缀表达式为:
21126-23*+
计算结果为:
159
输入非法,程序结束!
输入非法,程序结束!
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&it);
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;
break;
}
elseif(ch[i]==')'&&ch[i-1]!
='(')
coutk--;
i++;
}
if(coutk<0||coutk>0)
{
cout<<"括号不匹配!
"<exit(0);
}
建树:
算法利用两个临时的栈,一个存操作数,一个存操作符,检测到操作数,建立叶子节点,压入存入操作数栈,遇到操作符,存入操作符栈,每次存操作符时与前一个操作符做运算级别比较,若上一个操作符级别大,则弹出上一个操作符,同时弹出两个操作数建立二叉树,操作符做根节点,在把根节点压入操作数栈,括号做优先级最高处理,遇到右括号(前提是有了左括号和必要的运算式),操作符栈弹出,同时弹出两个操作数,建立二叉树,根节点压入操作数的栈。
BinTree:
:
BinTree(charexp[])//根据字符串exp的内容构建表达式树T
{
stackPTR;//存放表达式树中的节点指针
stackOPTR;//存放操作符
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++;
flag=true;
}
else
{
switch(exp[i])
{
case'(':
{
flag=true;
OPTR.push(exp[i]);
i++;break;
}
case')':
{
op=OPTR.top();OPTR.pop();
while(op!
='(')
{
flag=true;
CrtSubTree(PTR,op);//操作数栈建立分支节点
op=OPTR.top();OPTR.pop();
}//endwhile
i++;
break;
}
default:
//exp[i]是+-*/
while(!
OPTR.empty())
{
op=OPTR.top();
if(!
flag)
{
cout<<"不能有连续的两个运算符!
"<exit(0);
}
if(Precede(op,exp[i])=='>')//操作符比较优先级
{
CrtSubTree(PTR,op);
OPTR.pop();
}
if(exp[i]!
='#')
{
OPTR.push(exp[i]);
i++;
flag=false;
}
break;
}
}
}
}
root=PTR.top();//返回树的根节点
PTR.pop();
}
后序遍历:
voidpostorder(BinNode*subroot,char*exp,int&count)
{
if(subroot!
=NULL)
{
postorder(subroot->left(),exp,count);
postorder(subroot->right(),exp,count);
for(inti=0;ilength();i++)
exp[count++]=subroot->setVal(i);
exp[count++]='';
}
};
最后输出exp这个字符串,就是逆波兰表达式。
计算:
按照存在字符串中的后缀表达式,遇到数字转换为double实数,压入栈,遇到操作符,栈中弹出两元素,同时做运算(/除数不能问0),结果压入栈,知道剩下最后一个数字为止;
voidevaluate(charch[],double&result)
{
SqStackS;//运算栈
inti;
i=0;
while(ch[i]!
='#'&&i<100)
{
if(isdigit(ch[i]))
{
i+=EvalValue(&ch[i],S);//转换实数,压栈;
}
elseif(ch[i]=='')
i++;
else
{
EvalExpr(ch[i],S);//弹栈,做相应的运算;
i++;
}
}
if(S.length()==1)
result=S.pop();
}
result为最后的结果
intEvalValue(char*ch,SqStack&S)
{
inti=0;
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&S)
{
doubles1=0;
doubles2=0;
if(S.length()<2)
{
printf("\n表达式错误\n");
exit(0);
}
switch(ch)
{
case'+':
s1=S.pop();
s2=S.pop();
S.push(s2+s1);break;
case'-':
s1=S.pop();
s2=S.pop();
S.push(s2-s1);break;
case'*':
s1=S.pop();
s2=S.pop();
S.push(s2*s1);break;
case'/':
s1=S.pop();
s2=S.pop();
if(s1!
=0)
S.push(s2/s1);
else
{
cout<<"除数不能为0!
无结果!
"<exit(0);
}
break;
default:
printf("error");
}
}
算法的时空分析
此算法利用栈和二叉树来实现,故次算法的的时间复杂度为O(N)
输入和输出的格式
输入
本程序可以将输入的中缀表达式转化为后缀表达式,并输出计算结果
请输入表达式。
回车表示结束
输出
逆波兰表达式为为:
表达式值为:
4、测试结果
5、实验心得
四则运算表达式存入栈中,考虑到的情况十分的复杂,运算符的优先级和括号的问题,还有各种意外情况的处理,括号的匹配,十分麻烦,不愧是做的最复杂的实验;
6、附录
EX_4.cpp