第6章树和二叉树A文档格式.docx
- 文档编号:21066912
- 上传时间:2023-01-27
- 格式:DOCX
- 页数:53
- 大小:571.55KB
第6章树和二叉树A文档格式.docx
《第6章树和二叉树A文档格式.docx》由会员分享,可在线阅读,更多相关《第6章树和二叉树A文档格式.docx(53页珍藏版)》请在冰豆网上搜索。
D={Root}∪Df
其中,Root为树T的根结点,Df为树T的根Root的子树集合。
Df可由下式表示:
Df=D1∪D2∪…∪Dm且Di∩Dj=φ(i≠j,1≤i≤m,1≤j≤m)
当树T中结点个数n≤1时,R=φ;
当树T中结点个数n>
1时有:
R={<
Root,ri>
i=1,2,…,m}
中,Root为树T的根结点,ri是树T的根结点Root的子树Ti的根结点。
⑶凹入表示法
树的凹入表示法是是线段的伸缩关系描述树结构,它主要用于树的屏幕和打印机显示。
如图6.2是图6.1(b)所示的树的竖向凹入表示,还可有树的横向凹入表示。
图6.2
⑷文氏图表示法
使用集合以及集合的包含关系描述树结构,如图6.3图6.1(b)所示的树的文氏图表示。
⑸广义表表示法
先写出根,接着依次表示根的各棵子树,每进入一层就外加一对圆括号,即用嵌套圆括号来表示表中结点之间的层次关系。
如图6.1(b)所示的树结构可用广义表表示如下:
(A(B(E(J),F),C(G(K,L)),D(H,I)))
3.树的基本术语
⑴结点的度与树的度⑵叶结点与分枝结点⑶孩子、兄弟、双亲⑷祖先与子孙⑸结点的层数与树的深度
⑹堂兄弟⑺有序树和无序树⑻森林
⑴结点的度与树的度
树中结点所拥有的子树的个数称为该结点的度。
树中各结点度的最大值称为该树的度。
⑵叶结点与分枝结点
度为0的结点称为叶结点或终端结点。
度不为0的结点称为分枝结点或非终端结点。
⑶孩子、兄弟、双亲
树中一个结点的子树的根结点称为这个结点的孩子,相应地,这个结点称为它的孩子结点的双亲,具有同一个双亲的孩子结点互称为兄弟。
⑷祖先与子孙
一个结点的所有子树中的结点称之为该结点的子孙结点,结点的祖先是从根结点到该结点所经分枝上的所有结点。
⑸结点的层数与树的深度
树中的每一个结点都处在一定的层数上。
根结点的层数规定为1,其余结点的层数等于它的双亲结点的的层数加1。
树中所有结点的最大层次称为树的深度。
⑹堂兄弟
双亲在同一层的结点互为堂兄弟。
⑺有序树和无序树
如果一棵树中结点的各子树从左到右是有次序的,即若交换了某结点各子树的相对位置则构成不同的树,称这棵树为有序树;
反之,则称为无序树。
⑻森林
m(m≥0)棵不相交的树的集合称为森林。
自然界中树和森林是不同的概念,但在数据结构中,树和森林只有很小的差别,任何一棵树,删去根结点就变成了森林。
4.树的基本性质
性质1树中的结点数等于所有结点的度数加1。
性质2度为d的树中第i层上至多有di-1个结点(i≥1)。
性质3为k的d叉树至多有个结点。
性质4具有n个结点的d叉树的最小深度为
。
性质1
证明:
根据树的定义,在一棵树中,除根结点外,每个结点有且仅有一个前驱结点也就是说,每个结点与指向它的一个分支一一对应,所以除根结点之外的结点数等于所有结点的分支数(即度数),从而可得树中的结点数等于所有结点的度数加1。
性质2
用数学归纳法证明。
对于第1层显然是成立的,因为树中的第1层上只有一个结点,即整个树的根结点,而由i=1代入di-1计算,也同样得到只有一个结点,即di-1=d1-1=d0=1;
假设对于第i-1(i>
1)层命题成立,即度为d的树中第i-1层上至多有d(i-1)-1=di-2个结点,则根据树的度的定义,度为d的树中每个结点至多有d个孩子,所以第i层上的结点数至多为第i-1层上结点数的d倍,即至多di-2×
d=di-1,这与命题相同,故命题成立。
性质3
显然当深度为k的d叉树(即度为d的树)上每一层都达到最多结点数时,所有结点的总和才能最大,即整个d叉树具有最多结点数。
当一棵d叉树上的结点数等于时,则称该树为满d叉树。
性质4
设具有n个结点的d叉树的深度为k,若在该树中前k-1层都是满的,即每1层结点数都等于di-1(1≤i≤k-1)个,第k层(即最后一层)的结点数可能满,也可能不满,则该树具有最小的深度。
根据性质3,其深度k的计算公式可变换为:
dk-1<
n(d-1)+1≤dk
以d为底取对数后得:
k-1<
logd(n(d-1)+1)≤k
即:
logd(n(d-1)+1)≤k<
logd(n(d-1)+1)+1
因k只能是整数,所以:
k=
因此得到具有n个结点的一般d叉树的最小深度为
5.树的抽象数据类型
ADTTree{
Data:
树是由一个根结点和若干棵子树构成。
树中结点具有相同数据类型及层次关系。
Operation:
InitTree(&
T)
操作结果:
构造一棵空树T。
CreateTree(&
T,S)
初始条件:
串S是以广义表形式表示的树。
按S构造一棵树T。
OrderTree(T,Visit())
树T存在,Visit是对结点操作的应用函数。
按某种次序对T的每个结点调用函数Visit()一次且至多一次。
一旦visit()失败,则操作失败。
SearchTree(T,&
e)
树T存在。
在树T中查找元素e,若查找成功,返回true;
否则返回false。
PrintTree(T)
以某种形式输出树T。
TreeDepth(T)
求树T的深度。
DestroyTree(&
T)
撤销树T。
}ADTTree
6.1.2树的存储结构
1.双亲表示法2.孩子表示法3.双亲孩子表示法
1.双亲表示法
⑴双亲表示法的含义⑵双亲数组表示法⑶双亲链表表示法
⑴双亲表示法的含义
树的双亲表示法就是用指针表示出每个结点的双亲在存储空间的位置信息。
这种表示法的优点是容易寻找双亲结点,因而对于实现Parent(T,e)操作和Root(T)等操作很方便,其缺点是不容易找孩子结点,也不能反映各兄弟间的关系,因而对实现LeftChild(T,e)和RightSibling(T,e)等操作则比较困难。
⑵双亲数组表示法
双亲数组表示法就是用一维结构体数组依次存储树中的各结点,数组中的一个元素表示树中的一个结点,数组元素中包括结点本身的信息以及结点的双亲结点在数组中的下标。
对于图6.7(a)所示的树,它的双亲数组表示法如图6.7(b)所示,图中用-1表示相应的域为空。
其结构描述如下:
#defineMAX_TREE_SIZE100
typedefstruct{
TElemTypedata;
intparent;
}PTreeNode;
PTreeNodePTree[MAX_TREE_SIZE];
说明:
在树的相关操作中要调用栈和队列的相关操作,为了与栈和队列中的元素类型ElemType相区别,树中的元素类型用TElemType抽象。
同时约定下标为0的位置存储根结点。
图6.7
⑶双亲链表表示法
双亲链表表示法就是用一组任意的存储单元存储树中各结点,结点中包括结点本身的信息和指向该结点的双亲的指针。
因为树中除根结点外,每个结点只有一个双亲,所以这种表示法的结果是一个单链表。
2.孩子表示法
⑴孩子表示法的含义⑵孩子数组表示法⑶孩子链表表示法⑷左孩子右兄弟表示法
⑴孩子表示法的含义
树的孩子表示法就是用指针表示出每个结点的孩子在存储空间的位置信息。
这种表示法的优点是容易寻找孩子结点,因而对于实现LeftChild(T,e)和RightSibling(T,e)等操作很方便,其缺点是不容易找双亲结点,因而对实现Parent(T,e)操作和Root(T)等操作则比较困难。
由于树中的每个结点都可能有多个孩子结点,因此,可以令每个结点包括一个数据域和多个指针域,每个指针指向该结点的一个孩子结点(若无孩子结点,则相应的指针域置空)。
在这种表示法中,树中每个结点有多个指针域,形成了多条链表,因而又叫多重链表表示法。
又因为在一棵树中,各结点的度数各异,为了使结点的结构一致(为操作带来方便),一般选择树的度(即树中各结点度数的最大值)作为结点中指针域的个数,因而需要预先估计树的度的大小。
#defineMAX_SON_SIZE3//树的度
⑵孩子数组表示法
孩子数组表示法就是用一维结构体数组依次存储树中的各结点,数组中的一个元素表示树中的一个结点,数组元素中包括结点本身的信息以及结点的孩子在数组中的下标,结点中指针(相对指针)的个数等于树的度,若某结点无孩子,其相应的指针域为空(用-1表示)。
intchild[MAX_SON_SIZE];
}CTreeNode;
CTreeNodeCTree[MAX_TREE_SIZE];
对于图6.7(a)所示的树,它的孩子数组表示法如图6.8所示。
图6.8
⑶孩子链表表示法
孩子链表表示法就是用一组任意的存储单元存储树中各结点,结点中包括结点本身的信息和指向该结点的所有孩子的指针,结点中指针域的个数等于树的度数。
其结点结构描述如下:
typedefstructCTNode{
structCTNode*child[MAX_SON_SIZE];
}CTNode,*CTree;
对于图6.7(a)所示的树,它的孩子链表表示法如图6.9所示,其中root为指向根结点的指针。
此存储方法的优点是解决了结点结构不一致的问题,但当树中各结点的度数差别很大时,链域的利用率很低。
因为小于树的度的结点,结点的链域中有一部分为空指针。
图6.9
⑷左孩子右兄弟表示法
类似于孩子链表表示法,不同之处在于每个结点都只有两个指针域,左孩子域lchild和右兄弟域rsibling,其中lchild域指向本结点的最左边的孩子,简称为左孩子,rsibling域指向本结点的右边的第一个兄弟,简称为右兄弟。
若本结点无孩子,即为叶子,则lchild域为空指针;
若本结点右边无兄弟,则rsibling域为空指针。
在这种存储结构中,由于树中的每个结点只有两个指针域,所以又称这种方法为二叉链表表示法。
其结点的结构描述如下:
typedefstructLRTNode{
structLRTNode*lchild;
structLRTNode*rsibling;
}LRTNode,*LRTree;
对于图6.7(a)所示的树,它的左孩子右兄弟表示法如图6.10所示。
图6.10
3.双亲孩子表示法
⑴双亲孩子表示法的含义⑵双亲孩子数组表示法⑶双亲孩子链表表示法⑷双亲数组孩子链表表示法
⑴双亲孩子表示法的含义
如果在操作中既要方便寻找双亲,又要方便寻找孩子,则可将上述两种存储结构进行结合,即既存储双亲在存储空间中的位置,又存储孩子在存储空间中的位置,这就是双亲孩子表示法。
这种方法的优点是寻找双亲和孩子都比较方便,因而能够较方便地实现树的各种基本操作,但它是以牺牲空间为代价而换取时间的。
⑵双亲孩子数组表示法
这种表示法是用一维数组存储树中各结点,数组元素中包括结点本身的信息以及双亲结点和所有孩子结点在数组中的下标。
}PCTreeNode;
PCTreeNodePCTree[MAX_TREE_SIZE];
如果用PCTree表示图6.7(a)所示的树,则如图6.11所示。
图6.11
⑶双亲孩子链表表示法
双亲孩子链表表示法就是用一组任意的存储单元存储树中各结点,结点中除了指向孩子结点的指针域外,还增加一个指针域,以指向其双亲。
typedefstructPCTNode{
structPCTNode*parent;
structPCTNode*child[MAX_SON_SIZE];
}PCTNode,*PCTree;
对于图6.7(a)所示的树,它的双亲孩子链表表示法如图6.12所示。
图6.12
⑷双亲数组孩子链表表示法
这种方法是将双亲数组表示法和孩子链表表示法有机地结合,即把某个结点的所有孩子排列起来,并用单链表作为它的存储表示。
n个结点的树,用n个这样的单链表组成,每个单链表设立一个表头结点,它有3个域:
数据域data表示树的一个结点的数据信息,指针域(下标)parent为该结点的双亲在数组中的下标,指针域link指向该结点的孩子单链表的第一个结点。
n个这样的表头结点用一维数组表示。
typedefstructNode{
intchild;
structNode*next;
}CNode;
CNode*Childlink;
}PCLink;
PCLinkPCLTree[MAX_TREE_SIZE];
如果用PCLTree表示图6.7(a)所示的树,则如图6.13所示。
图6.13
6.1.3树的基本操作
1.初始化2.创建树3.树的遍历4.查找5.树的输出6.求树的深度7.树的撤销
1.初始化
voidInitTree(CTree&
{
T=NULL;
}//InitTree
2.创建树
⑴算法思想⑵算法描述
⑴算法思想
创建一棵树就是在内存中生成一棵树的存储映象,即孩子链表。
因为树是一种层次结构,创建树的操作首先需要确定输入树的方法,然后再写出相应的算法。
不同的输入方法,树的创建算法也不同。
如果采用广义表的形式输入,对于图6.7(a)所示的三叉树,得到的广义表表示为:
A(B(D,E(H,I),F),C(G))
其中,假定每个结点的非空子树都是靠前面、按序排列的子树,把所有空子树都留在后面。
在实际情况中可能会出现缺少前面子树而存在后面子树的情况,此时用广义表表示时空子树后面的逗号不能省略。
在树的生成算法中,需要设置两个栈,一个用来存储指向根结点的指针,以便孩子结点向双亲结点链接之用;
另一个用来存储待链接的孩子结点的序号,以便能正确地链接到双亲结点的指针域。
若这两个栈分别用stack和d表示,stack和d栈的深度不会大于整个树的深度。
⑵算法描述
#defineMS10//栈空间的大小
voidCreateTree(CTree&
T,char*S)
CTreestack[MS],p;
inti=0,d[MS],top=-1;
while(S[i])
{switch(S[i])
{case'
'
:
break;
case'
('
top++;
stack[top]=p;
d[top]=0;
)'
top--;
'
d[top]++;
default:
if(!
(p=(CTree)malloc(sizeof(CTNode))))exit
(1);
p->
data=S[i];
for(inti=0;
i<
MAX_SON_SIZE;
i++)
p->
child[i]=NULL;
T)T=p;
elsestack[top]->
child[d[top]]=p;
}
i++;
}//CreateTree
3.树的遍历
⑴树的遍历的含义⑵树的遍历的规则⑶树的遍历的算法描述
⑴树的遍历的含义
树的遍历就是如何按某条搜索路径巡访树中每个结点,使得每个结点均被访问到且仅被访问一次。
这里“访问”的含义十分广泛,包括按问题需求对结点所进行的任何存取操作或其他加工任务。
为了使遍历操作的含义更为广泛,在下面的遍历算法描述中,将结点的访问操作抽象为一个函数Visit(),待具体应用遍历算法时再根据需要确定相关操作。
⑵树的遍历的规则
因为树是一种非线性结构,每个结点都可能有多个后继,因而需要按照一定的规律,使树中的结点能被访问且仅被访问一次。
对于树这种层次结构,访问的次序一般有三种,即先(根)序遍历(或称深度优先遍历)、后(根)序遍历和层序遍历(或称广度优先遍历)。
先序遍历:
先访问根结点,然后从左到右依次先根遍历每棵子树,此遍历过程是一个递归过程。
后序遍历:
先从左到右依次后根遍历根结点的每棵子树,然后再访问根结点,此遍历过程也是一个递归过程。
层序遍历:
从树的第一层(根结点)开始,从上至下逐层遍历,在同一层中,则按从左到右的顺序逐个访问。
直到全树中的所有结点都被访问为止,或者说直到访问完最深一层结点为止。
⑶树的遍历的算法描述
1先序遍历②后序遍历③层序遍历
2①先序遍历
voidPreOrderTree(CTreeT,voidVisit(TElemType))
if(T)
{
Visit(T->
data);
PreOrderTree(T->
child[i],Visit);
}
}//PreOrderTree
②后序遍历
voidPostOrderTree(CTreeT,voidVisit(TElemType))
{
PostOrderTree(T->
}//PostOrderTree
③层序遍历
typedefCTreeElemType;
voidLevelOrderTree(CTreeT,voidVisit(TElemType))
SqQueueQ;
CTreep;
InitQueue_Sq(Q,MAX_TREE_SIZE,10);
if(T)EnQueue_Sq(Q,T);
while(!
QueueEmpty_Sq(Q))
{DeQueue_Sq(Q,p);
Visit(p->
i++)
if(p->
child[i])EnQueue_Sq(Q,p->
child[i]);
}//LevelOrderTree
4.查找
boolSearchTree(CTreeT,TElemType&
T)returnfalse;
else{
if(T->
data==e)
{e=T->
data;
returntrue;
if(SearchTree(T->
child[i],e))returntrue;
returnfalse;
}//SearchTree
5.树的输出
voidPrintTree(CTreeT)
{//以广义表形式输出按孩子链表存储的树
inti;
if(T){
cout<
<
T->
data<
'
;
for(i=0;
child[i])break;
if(i<
MAX_SON_SIZE)
{cout<
PrintTree(T->
child[0]);
for(i=1;
{if(T->
child[i])cout<
}//PrintTree
6.求树的深度
intTreeDepth(CTreeT)
T)return0;
intmax=0;
{intk=TreeDepth(T->
if(k>
max)max=k;
returnmax+1;
}//TreeDepth
7.树的撤销
voidDestroyTree(CTree&
{
if(T)
DestroyTree(T->
free(T);
}//DestroyTree
6.2二叉树
6.2.1二叉树的基本概念
1.二叉树的定义2.特殊形态的二叉树3.二叉树的抽象数据类型4.二叉树的基本性质
1.二叉树的定义
二叉树是n(n≥0)个结点的有限集合,这个集合或者为空,或者由一个称作根结点及两个不相交的、被分别被为在左子树和右子树的二叉树组成。
当二叉树中结点个数n=0时,称为空二叉树。
图6.14给出了一棵二叉树的示意图,图6
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第6章 树和二叉树A 二叉
![提示](https://static.bdocx.com/images/bang_tan.gif)