北工大数据结构上机实验报告3教材.docx
《北工大数据结构上机实验报告3教材.docx》由会员分享,可在线阅读,更多相关《北工大数据结构上机实验报告3教材.docx(18页珍藏版)》请在冰豆网上搜索。
![北工大数据结构上机实验报告3教材.docx](https://file1.bdocx.com/fileroot1/2023-2/25/80cb9c4a-5001-4e7e-86d7-535cdd01d866/80cb9c4a-5001-4e7e-86d7-535cdd01d8661.gif)
北工大数据结构上机实验报告3教材
上机题三报告
姓名:
学号:
完成日期:
2015年5月5日
题目:
表达式可以用表达式二义树来表示。
对于简单的四则运算表达式,请实现以下功能;
(1)对于任意给出的前缀表达式(不带括号)、中缀表达式(可以带括号)或后缀表达式(不带括号),能够在计算机内部构造出一棵表达式二义树,并且以图示显示出来(字符图或图形的形式)。
(2)对于构造好的内部表达式二叉树,按照用户要求,输出相应的前缀表达式(不带括号)、中缀表达式(可以带括号)或后缀表达式(不带括号).
一、需求分析
1.输入形式、输入值的范围;输入前缀表达式(不带括号)、中缀表达式(可以带括号)或后缀表达式(不带括号)
2.输出形式^表达式二叉树,前缀表达式、中缀表达式和后缀表达式。
3・程序功能;用表达式二叉树表示表达式,并转换为前缀表达式、中缀表达式或后缀表达式。
4.测试数据
正确的输入输出:
为为为达达达表表表241
错误的输入输出:
请输入字符串表达式:
23+11/304
1/
34
中缀表达式为=1+3/4雪建i轲为=必4后缀衾达式为=134/+
二、概要设计
1.ADT定义
classTNode//W点类
2.主程序流程
3.各程序模块间的调用关系
Main()
求二叉树表达式模块
求前、中、后缀表达式模块
打印树
删除树
三、详细设计
1.实现ADT定义的数据类型
classTNode//节点类
{public:
charoper;//数据域,为简便起见,操作数用单个字符代替
TNode*left;
TNode*right;
ints;intt;〃计算树的层数使用
TNode()//缺省构造函数
{left二right二NULL;
opei-O;
}
TNode(charop)//赋值构造函数
{left二right二NULL;
opei-op;
}
1;
2.算法描述
表达式转化为二叉树
voidpre2tree(TNode*&p,stringstr)//#缀表达式生成二叉树
{碰到操作数则把英值赋给相应的新申请的二叉树结点,地址压栈:
碰到操作符则把其值赋给相应的新申请的二叉树,并从栈中弹出两个地址,
分别作为英左指针和右指针,然后再把其地址压栈,最后一个地址即为二叉树的根结点地址。
)
voidpost2tree(TNode*&p^stringstr)//后缀表达式生成二叉树
{〃碰到操作数则把英值赋给相应的新申请的二叉树结点,若栈为空则地址压栈,
〃碰到操作符则把其值赋给相应的新申请的二叉树结点,取栈顶元素,
〃若当前元素的左孩子为空则设为其左孩子,
〃左孩子为满则设为其右孩子,开始那个元素地址为根结点地址,开始时用变量root保存。
}
voidin2tree(TNode*&p,stringstr)//中缀表达式转换成后缀表达式生成二叉树
{从中缀表达式中自左至右依次读入各个字符。
如果读入操作数,直接输出到后缀表达式。
如果读入的是运算符,并且运算符栈为空,则将该运算符宜接进栈:
如果栈不
为空,则比较该运算符和栈顶运算符的优先级。
若该运算符高于栈顶运算符的优先级,则将该运算符直接进栈:
若该运算符低于或等于栈顶运算符的优先级,则将栈中高于或等于该运算符优先
级的元素依次出栈输出到后缀表达式中,然后再将该运算符进栈。
在碰到开括号和栈为空前反复弹出栈中元素
若栈非空栈顶不是左括号且栈顶元素优先级不低于输入运算符时,
/将栈顶元素弹岀到后缀表达式
}
二叉树表达式转化为表达式
voidpostOrdcr(TNode*p)〃先序遍历
{if(P)
{postOrder(p->left);
postOrder(p->right);
cout«p->oper;
)
}
voidpreOrder(TNode*p)//后序遍历
{if(P)
{cout«p->oper;
preOrder(p->left);
preOrder(p->right);
voidinOrder(TNodc幺p)〃中序遍历,同时输出不带冗余括号的中缀表达式
{if(P)
if(p->left)
{if(如果当前节点的左子树是运算符,且运算符优先级低于当前运算符,
那么左边的表达式要先il•算,需要加括号)
{
cout«H(H;
inOrder(p->left);
cout«H)M;
}
else//否则直接输出左子树
inOrdcr(p->left);
}
cout«p->opcr;〃输出当前巧点
if(p->right)
{if(如果当前节点的右子树是运算符,且运算符优先级不高于当前运算符,
那么右边的表达式要先计算,需要加括号)
{
cout«H(n;
inOrder(p->right);
cout«,r)M;
}
else
inOrder(p->right);
四、程序测试
n
Pl
鬧输入字符串表达式,
-*4-2325
3■■:
r
駡输入字符串表达式:
K2+3)*2-5
吃5-
M2石
>3兴
+3+2吃
2*3
<-2第知站迄达2表表表
*3缀缀缀+2虫聲
養输入字符串表达式:
23+2*5-
为为为达达达表表表3缀缀缀2中曹
五、用户使用说明
运行程序后,按照提示选择表达式类型(-1:
前缀表达式;0:
中缀表达式:
1:
后缀表达式)然后输入相应的表达式,回车后可以得到二叉树表达式及出前缀、中缀、后缀表达式
六、源程序
#include
#includc
#includc
#include
#include
usingnamespacestd;
classTNode//节点类
{public:
charoper7/数据域,为简便起见,操作数用单个字符代替
TNode*left;
TNode*right;
ints;intW树的层数使用
TNode()//缺省构造函数
{Ieft=right=NULL;
oper=0;
}
TNode(charop)//赋值构造函数
{left=right=NULL;
oper=op;
}
};
boolisOper(charop)〃判断是否为运算符
{
charoper[]={,(,;)\,+,,'-',
for(inti=0;ii++)
{if(op=oper[i])
{
returntme;
}
)
returnfalse;
}
intgetOperOrder(charop)//返回运算符op所对应的优先级
{//左括号优先级,加减号为,乘除号为,方幕为,右括号,栈底返回switch(op){caser:
return1;
case屮:
case"clum2;
case
case7:
return3;case,A,:
return4;default:
〃龙义在栈中的右括号和栈底字符的优先级最低
return0;
}
)
voidfreeTree(TNode*&p)//递归删除树
{
if(p->left!
=NULL)
freeTree(p->left);
if(p->right!
=NULL)freeTree(p->right);
delete(p);
}
voidpostOrder(TNode*p)〃先序遍历
{if(P)
{postOrder(p->left);
postOrder(p->right);
cout«p->oper;
}
}
voidpreOrder(TNodc*p)//后序遍历
{if(P)
{cout«p->oper;
preOrder(p->left);
preOrder(p->right);
}}
voidinOrder(TNode幺p)〃中序遍历,同时输出不带冗余括号的中缀表达式
{if(P)
{
if(p->left)
{//如果当前节点的左子树是运算符,且运算符优先级低于当前运算符,
〃那么左边的表达式要先计算,需要加括号
if(isOper(p->left->opcr)&&gctOpcrOrdcr(p・>lcft・>opcr)vgctOpcrOrdcr(p・>opcr))
{
cout«n(n;
inOrder(p->left);
cout«,i)M;
}
else//否则直接输岀左子树
inOrdcr(p->left);
coulvvp・>opcr;〃输出当前盯点
if(p->right)
{〃如果当前节点的右子树是运算符,且运算符优先级不髙于当前运算符,
〃那么右边的表达式要先计算,需要加括号
if(isOper(p->right->opcr)&&gctOpcrOrdcr(p・>righJ>opcr)v=gctOpcrOrdcr(p〉opcr)){
cout«H(n;
inOrder(p->right);
cout«,,)M;
}
else
inOrder(p->right);
}
}
)
voidpost2tree(TNode*&p,stringstr)//后缀表达式生成二叉树
{//(a)碰到操作数则把其值赋给相应的新申请的二叉树结点,若栈为空则地址压栈,
//(b)碰到操作符则把其值赋给相应的新申请的二叉树结点,取栈顶元素,
〃若当前元素的左孩子为空则设为其左孩子,
〃左孩子为满则设为其右孩子,开始那个元素地址为根结点地址,开始时用变量root保存。
stacknodeStack;//用于保存节点指针的栈
chartemp;
inti=0;
temp=str[i++];
whilc(tcmp!
=、(y)
{
if(temp!
=\0,&&!
isOper(temp))//不是运算符,则进栈
{
p=newTNode(temp);//以temp为结点值构造二叉树结点nodeStack.push(p);
temp=str[i++]y/读入F—个
}
else
{〃如果遇到符号,则弹栈,依次设为右节点和左节点
p=newTNode(temp);
if(nodcStack.sizeO)
{
p->right=nodeStack.top();//若非空则弹栈并设为结点的右孩子
nodcStack.popO;
if(nodcStack.sizeO)
{p->left=nodcStack.top();〃若非空则禅栈并设为结点的左孩子
nodcStack.popO;
}
nodeStack.push(p);
temp=str[i++];
}
}
}
voidpre2tree(TNode*&p.stringstr)//前缀表达式生成二叉树
{//碰到操作数则把其值赋给相应的新申请的二叉树结点,地址压栈:
〃碰到操作符则把其值赋给相应的新申请的二叉树,并从栈中弹出两个地址,
〃分别作为其左指针和右指针,然后再把其地址压栈,最后一个地址即为二叉树的根结点地址。
stacknodeStack;
chartemp;
inti=str.size()-l;
temp=str[i-];
while(temp!
=f\Or)
{
if(temp!
=\0*&&JisOper(tenip))
{p=newTNode(temp)7/以temp为内容来建立新的结点
nodcStack.push(p);
temp=str[i-];}
else
{p=newTNode(temp);
if(nodeStack.size())//栈非空
{p->left=nodeStack.top();〃则栈顶指针所指结点设it成当前结点左孩子
nodcStack.popO;
}
if(nodcStack.sizc())〃栈非空
{p->right=nodeStack.top()7/则栈顶指针所指结点设置成当前结点右孩子
nodeStack.popO;〃栈顶元素左右孩子指针设置完毕弹岀
}
nodeStack.push(p);
temp=str[i-];
}
}〃当栈空且扫描到最后时,树根由P带回
voidin2tree(TNode*&p.stringstr)//中缀表达式转换成后缀表达式生成二叉树
stacka;
chartemp;
stringPostfixexp=,H,;
inti=0;
temp=str[i++];
whilc(icmp!
=、(K)
{
if(!
isOpcr(tcmp))〃操作数则宜接进数据栈
{Postfixexp+=temp;
temp=str[i++];
}
elseif(temp==,(,)//进栈
{
a.push(temp);temp=str|i++J;
}
elseif(temp=,)')
{
whilc(a」op()!
=()//脱括号
{
Postfixexp+=a.top();
a.pop();〃在碰到开括号和栈为空前反复弹岀栈中元素
}
a.popO;
temp=str[i++);
}
elseif(temp=,+,lltemp=-1ltemp==,*,lltemp==7)//出栈
{
while(!
a.empty()&&a.top()!
=C&&getOperOrder(a.top())>=getOperOrder(temp))
〃若栈非空栈顶不是左括号且栈顶元素优先级不低于输入运算符时,
//将栈顶元素弹岀到后缀表达式中,并且str下标加
{Postfixexp+=a.top();a.pop();}
a.push(temp);
temp=str[i++];
}
}//endwhile(temp!
=W)
while(!
a.einpty())
{Postfixexp+=a.top();
a.popO;
}
Postfixexp+=W\
//cout«Postfixexp:
post2tree(p.Postfixexp);
}
voidcount(TNode*pjnt&heightjntn)〃求值函数
{//求树的高度
if(p->left=NULL&&p->righl=NULL)
{if(n>height)
height=n;}
if(p->left!
=NULL)
count(p->left,height.n+l);
if(p->right!
=NULL)
count(p->right,height.n+1);
}
voidpaint(TNode水p)//打印树
{
intheight=O;
inth=0;
inti;
usingstd:
:
queue:
queueaQueue:
count(p,height」);
TNode*pointer=p;
TNode*lastpointer;
if(pointer)
{pointer->s=l;
pointer->t=l;
aQueue.push(pointer);}
while(!
aQueue.empty())
{lastpointer=pointer;
pointer=aQueue.front();
aQucue.popO;
if(pointer->s>h)
{cout«endl;
h=pointer->s;}
if(pointer->t==l)
{for(i=0;is)-1;i++)
cout«H”;}
elseif(lastpointer->s!
=pointer->s){
for(i=0;i<(pointer->t-1)*(pow(2,height-pointer->s+1)-1)+(pointer->t-1)-1+pow(2.height-pointer->s);i++)
cout«,rM;}
else
{for(i=0;i<(pointer->t-lastpointer->t)*(pow(2,height-pointer->s+1)-1)+(pointer->t-lastpointer->t)-l;i++)
cout«HH;}
cout«pointer->opcr;
if(pointer->left!
=NULL){
pointer->left->s=pointer->s+1;
pointer->left->t=pointer->t*2-l;
aQueue.push(pointer->Ieft);}
if(pointer->right!
=NULL){
pointer->right->s=pointer->s+1;pointer->right->t=pointer->t*2;
aQueue.push(pointer->right);
}}}
intmain()
{
stringexpression;
TNode*tree;
cout«"请输入表达式类型,前缀表达式输入-1,中缀表达式输入0后缀表达式输入lM«endl;
intflag;
cin»flag;
coutvv"请输入字符串表达式:
H«endl;
cin»expression:
if(flag=-l)//那么是前缀表达式
pre2tree(tree,expression);
elseif(flag==l)//那么是后缀表达式
post2tree(tree,expression);
else//否则中缀表达式
in2tree(tree,expression);
paint(trec);
cout«endl:
cout«"中缀表达式为:
“;
inOrder(tree);
cout«endl;
cout«"前缀表达式为:
“;
preOrder(tree);
cout«endl;
cout«"后缀表达式为:
";
postOrder(tree);
cout«endl;freeTree(tree);cout«endl;
return0;