第9章 树.docx
- 文档编号:8590937
- 上传时间:2023-02-01
- 格式:DOCX
- 页数:30
- 大小:191.41KB
第9章 树.docx
《第9章 树.docx》由会员分享,可在线阅读,更多相关《第9章 树.docx(30页珍藏版)》请在冰豆网上搜索。
第9章树
第9章树
树型结构是一种重要的非线性结构,在计算机科学中有着广泛的应用。
在微型计算机的操作系统中,文件和文件夹(目录)就是以树型结构存储的,这为日益扩大的存储器和系统文件的管理提供了最大的方便;在编译程序中,可以用树来表示源程序的语法结构;在数据库系统中树型结构是信息的重要组织形式之一。
树是以分支关系定义的层次结构,其中尤其以二叉树最为常用。
9.1 树的基本概念
9.1.1 树的定义
树(Tree)是n(n≥0)个有限数据元素的集合。
在任意一棵非空树T中:
(1)有且仅有一个特定的称为树根(Root)的结点(根结点无前驱结点);
(2)当n>1时,除根结点之外的其余结点被分成m(m>0)个互不相交的集合T1,T2,…,Tm,其中每一个集合Ti(1≤i≤m)本身又是一棵树,并且称为根的子树。
树的定义采用了递归定义的方法,即在树的定义中又用到树的概念,这正好反映了树的固有特性。
图9.1是树的结构示意图。
层次
1
2
3
4
图9.1 树结构示意图
9.1.2 树的基本术语
结点——树的结点包含一个数据及若干指向其子树的分支。
结点的度——结点所拥有的子树数称为该结点的度(Degree)。
树的度——树中各结点度的最大值称为该树的度。
叶子(终端结点)——度为零的结点称为叶子结点。
分支结点——度不为零的结点称为分支结点。
兄弟结点——同一父亲结点下的子结点称为兄弟结点。
层数——树的根结点的层数为1,其余结点的层数等于它双亲结点的层数加1。
树的深度——树中结点的最大层数称为树的深度(或高度)。
森林——零棵或有限棵互不相交的树的集合称为森林。
在数据结构中,树和森林并不象自然界里有一个明显的量的差别。
任何一棵树,只要删去根结点就成了森林,见图9.2。
(a)树(b)移去根结点后成为森林
图9.2 树与森林关系图
有序树和无序树——树中结点的各子树从左到右是有次序的(即不能互换位置),称这样的树为有序树;否则称为无序树。
9.2 树的存储结构
9.2.1 双亲表示法
以一组连续的存储空间存放树的结点,每个结点中附设一个指针指示其双亲结点在这连续的存储空间中的位置(下标,这种结构属静态链表),其形式说明如下:
typrdefstructtnode /*节点结构*/
{datatypedata;
intparent;/*双亲位置域*/
}tree[n];
例如,图9.3展示了一棵树及其双亲表示的存储结构。
图9.3双亲表示法示例
9.2.2 孩子表示法
在孩子表示法中有一种称为孩子链表的表示方法:
把每个结点的孩子结点链在一个单链表中,则n个结点有n个孩子链表。
而n个头指针又组成一个线性表,为了便于查找,可采用顺序存储结构。
其形式描述如下:
typedefstructtagnode/*表结点即孩子结点*/
{intchild;
structtagnode*next;
}*link;
typedefstruct/*头结点*/
{datatypedata;
linkheadptr;/*孩子链表头指针*/
}headnode;
typedefheadnodechildlink[maxnode];
/*表头数组*/
图9.3中的二叉树用孩子链表可表示如下:
9.2.3 孩子兄弟表示法
该方法又称二叉树表示法,或二叉链表表示法,即以二叉链表作存储结构,结点的两个链域分别指向该结点的第一个孩子和下一个兄弟,分别命名为fch和nsib。
其形式描述如下:
typedefstructtreenode
{datatypedata;
structtreenode*fch,*nsib;
}treenode,*tree;
图9.3中的二叉树用孩子兄弟表示法可表示如下:
9.3 二叉树
9.3.1 二叉树的定义和性质
1. 定义
二叉树是有n(n>=0)个结点的有限集合。
(1)该集合或者为空(n=0);
(2)或者由一个根结点及两个不相交的分别称为左子树和右子树组成的非空树;
(3)左子树和右子树同样又都是二叉树。
通俗地讲,在一棵非空的二叉树中,每个结点至多只有两棵子树,分别称为左子树和右子树,且左右子树的次序不能任意交换。
所以,二叉树是特殊的有序树。
2. 二叉树的形态
根据定义,二叉树可以有五种基本形态,如图9.4所示。
(a)(b)(c)(d)(e)
图9.4二叉树的基本形态
其中:
(a)空二叉树;
(b)仅有根结点的二叉树;
(c)右子树为空的二叉树;
(d)左子树为空的二叉树;
(e)左、右子树均非空的二叉树。
3. 二叉树的基本操作:
二叉树的基本操作通常有以下几种:
(1)CreateBT():
创建一棵二叉树。
(2)ShowTree(BT*T):
按凹入法(或圆括号法等方法)显示二叉树。
(3)Preorder(BT*T):
按先序(根、左、右)遍历二叉树上所有结点。
(4)Inorder(BT*T):
按中序(左、根、右)遍历二叉树上所有结点。
(5)Postorder(BT*T):
按后序(左、右、根)遍历二叉树上所有结点。
(6)Levelorder(BT*T):
按层次遍历二叉树上所有结点。
(7)Leafnum(BT*T):
求二叉树叶结点总数。
(8)TreeDepth(BT*T):
求二叉树的深度。
4. 二叉树的性质
性质1一棵非空二叉树的第i层上最多有2i–1个结点(i≥1)。
一棵非空二叉树的第一层有1个结点,第二层最多有2个结点,第三层最多有4个结点……,利用归纳法即可证明第i层上最多有2i–1个结点。
性质2深度为h的二叉树中,最多具有2h-1个结点(h≥1)。
证明:
根据性质1,当深度为h的二叉树每一层都达到最多结点数时,它的和(n)最大,即:
n=xi≤2i–1=20+21+22+……+2h–1=2h‐1
∴命题正确。
(1)满二叉树
一棵深度为h,且有2h‐1个结点的二叉树称为满二叉树。
图9.5所示是一棵深度为4的满二叉树,其特点是每一层上的结点都具有最大的结点数。
如果对满二叉树的结点进行连续的编号,约定编号从根结点起,从上往下,自左向右(如图9.5),由此可以引出完全二叉树的定义。
图9.5满二叉树
(2)完全二叉树
深度为h,有n个结点的二叉树,当且仅当每一个结点都与深度为h的满二叉树中编号从1至n的结点一一对应时,称此二叉树为完全二叉树。
如图9.6(a)所示为一棵完全二叉树,而(b)则不是完全二叉树。
(a)一棵完全二叉树(b)一棵非完全二叉树
图9.6
完全二叉树除最后一层外,其余各层都是满的,并且最后一层或者为满,或者仅在右边缺少连续若干个结点。
性质3对于一棵有n个结点的完全二叉树,若按满二叉树的同样方法对结点进行编号,(见图9.5)则对于任意序号为i的结点,有:
(1)若i=1,则序号为i的结点是根结点。
若i>1,则序号为i的结点的父结点的序号为└i/2┘;
(2)若2i≤n,则序号为i的结点的左孩子结点的序号为2i;
若2i>n,则序号为i的结点无左孩子。
(3)若2i+1≤n,则序号为i的结点的右孩子结点的序号为2i+1;
若2i+1>n,则序号为i的结点无右孩子。
证明略。
性质4具有n(n>0)个结点的完全二叉树(包括满二叉树)的深度(h)为
。
证明:
由性质2和完全二叉树定义可知,当完全二叉树的深度为h、结点个数为n时,有:
2h-1–1 即2h-1≤n<2h 对不等式取对数有: h–1≤log2n 由于h是整数,所以有h= 。 性质5对于一棵非空的二叉树,设n0、n1、n2分别表示度为0、1、2的结点个数, 则有: n0=n2+1。 证明: (1)设n为二叉树的结点总数,则有: n=n0+n1+n2(9-1) (2)由二叉树的定义可知,除根结点外,二叉树其余结点都有唯一父结点, 那么父结点的总数(F)为: F=n–1(9-2) (3)根据假设,各结点的子结点总数(C)为: C=n1+2n2(9-3) (4)因为父子关系是相互对应的,即F=C,也即: n–1=n1+2n2(9-4) 综合(6-1)、(6-2)、(6-3)式可以得到: n0+n1+n2=n1+2n2+1 n0=n2+1 ∴命题正确。 9.3.2 二叉树的存储结构 二叉树的存储结构也有顺序存储和链式存储两种存储结构。 1. 顺序存储结构 二叉树的顺序存储,就是用一组连续的存储单元存放二叉树中的结点。 一般可以采用一维数组或二维数组的方法进行存储。 (1)一维数组存储法 对于一般的二叉树,如果按从上至下和从左到右的顺序将树中的结点顺序存储在一维数组中,则数组元素下标之间的关系不能够反映二叉树中结点之间的逻辑关系,只有增加一些并不存在的空结点,使之成为一棵完全二叉树的形式,才能用一维数组进行存储。 图9.7(a)为一棵一般二叉树,经过改造以后成为图9.7(b)所示的完全二叉树。 其顺序存储状态示意图如图9.7(c)。 1 23 56 101213 (a)一般二叉树(b)改造为完全二叉树 结点编号: 1 2 3 4 5 6 7 8 9 10 11 12 13 A B C ∧ D E ∧ ∧ ∧ F ∧ G H 数组下标: 0 `1 2 3 4 5 6 7 8 9 10 11 12 (c)二叉树在一维数组的存储 图9.7一般二叉树的顺序存储示例 显然,这种存储结构会造成空间的大量浪费,如图9.8(a)所示,一棵4个结点的二叉树,却要分配14个存储单元。 可以证明,深度为h的(右向)单支二叉树,虽然只有h个结点,却需分配2h-1个存储单元。 1 3 7 14 (a)原二叉树(b)改造后的完全二叉树 结点编号: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A ∧ B ∧ ∧ ∧ C ∧ ∧ ∧ ∧ ∧ ∧ D 数组下标: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 (c)二叉树改造后的顺序存储状况 图9.8特殊二叉树的顺序存储示例 对于完全二叉树和满二叉树。 这种顺序存储结构既能够最大限度地节省存储空间,又可以利用数组元素的下标值确定结点在二叉树中的位置,因为完全二叉树上编号为i的结点元素存储在一维数组中下标为i–1的分量中。 (2)二维数组存储法 设二叉树的结点数为n,可以将二维数组的容量定义为[n][3],即n行3列。 需要说明的是,在C语言中数组的下标是从0开始计数的。 仍以图9.7(a)的二叉树为例,并按二维数组存储的下标重新对结点编号如图9.9(a),设data为结点数据,leftno为结点左子树号,rightno为结点右子树号,则其存储表示如图9.9(b)所示: 0 data leftno rightno [0] [1] [2] 1 2 [0] A 1 2 [1] B 0 3 31 4 [2] C 4 0 [3] D 5 0 6 5 7 [4] E 6 7 [5] F 0 0 [6] G 0 0 [7] H 0 0 (a)(b) 图9.9 一般二叉树的二维数组存储示例 2. 链式存储结构 二叉树的链式存储结构是用链表来表示二叉树,即用链指针来指示结点的逻辑关系。 通常有下面两种形式。 (1)二叉链表存储 二叉链表结点由一个数据域和两个指针域组成,其结构如下: 其中: data为数据域,存放结点的数据信息; lchild为左指针域,存放该结点左子树的存储地址; rchild为右指针域,存放该结点右子树的存储地址。 当左子树或右子树不存在时,相应指针域值为空,用符号∧表示。 设一棵二叉树如图9.10所示,其二叉链表的存储表示如图9.11所示。 BT 图9.10一棵二叉树图9.11二叉树的链式存储示意图 二叉链表是二叉树最常用的存储方式。 本书所涉及的二叉树的链式存储结构一般都是指二叉链表结构。 下面给出二叉树的二叉链表描述: typedefstructBT/*定义二叉树结构体*/ {chardata;/*定义数据域*/ structBT*lchild;/*定义结点的左指针*/ structBT*rchild;/*定义结点右指针*/ }BT;/*将BT定义为指向二叉树结点结构体的指针类型*/ (2)三叉链表存储 三叉链表结点由一个数据域和三个指针域组成,其结构如下: 其中: data为数据域,存放结点的数据信息; lchild为左指针域,存放该结点左子树的存储地址; rchild为右指针域,存放该结点右子树的存储地址。 parent为父指针域,存放结点的父结点存储地址。 这种存储结构既便于查找左、右子树的结点,又便于查找父结点;但付出的代价是,增加了存储空间的开销。 图9.12给出了图9.10所示的二叉树的三叉链表存储示意图。 图9.12二叉树的三叉链表存储示意图 9.4 二叉树的遍历 二叉树的遍历是指按某种顺序访问二叉树中的所有结点,使得每个结点都被访问,且仅被访问一次。 通过一次遍历,使二叉树中结点的非线性序列转变为线性序列。 也就是说,使得遍历的结点序列之间有一个一对一的关系。 由二叉树的递归定义可知,一棵二叉树由根结点(D)、根结点的左子树(L)和根结点的右子树(R)三部分组成。 因此,只要依次遍历这三部分,就可以遍历整个二叉树。 若以D、L、R分别表示访问根结点、遍历根结点的左子树、遍历根结点的右子树,则二叉树的遍历方式有六种不同的排列方式: DLR、LDR、LRD、DRL、RDL和RLD。 如果限定先左后右的次序,那么就只有: DLR、LDR和LRD三种遍历。 9.4.1 二叉树的中根遍历 中序遍历也称为中根遍历,其递归过程为: 若二叉树为空,遍历结束;否则, 1)中序遍历根结点的左子树; 2)访问根结点; 3)中序遍历根结点的右子树。 中序遍历递归算法: voidInorder(BT*T)/*中序遍历二叉树BT*/ {if(T==NULL)return;/*递归调用的结束条件*/ {Inorder(T->lchild);/*中序递归遍历左子树*/ printf(T->data);/*输出结点的数据域*/ Inorder(T->rchild);/*中序递归遍历右子树*/ } } 对于图9.10所示的二叉树,按中序遍历所得到的结点序列为: DGBAECHF 9.4.2 二叉树的先根遍历 先序遍历也称为先根遍历,其递归过程为: 若二叉树为空,遍历结束。 否则, 1)访问根结点; 2)先序遍历根结点的左子树; 3)先序遍历根结点的右子树。 先序遍历递归算法: voidPreorder(BT*T)/*先序遍历二叉树BT*/ {if(T==NULL) return;/*递归调用的结束条件*/ {printf(T->data);/*输出结点的数据域*/ Preorder(T->lchild);/*先序递归遍历左子树*/ Preorder(T->rchild);/*先序递归遍历右子树*/ } } 对于图9.10所示的二叉树,按先序遍历所得到的结点序列为: ABDGCEFH 9.4.3 二叉树的后根遍历 后序遍历也称为后根遍历,其递归过程为: 若二叉树为空,遍历结束。 否则, 1)后序遍历根结点的左子树; 2)后序遍历根结点的右子树。 3)访问根结点; 后序遍历递归算法: voidPostorder(BT*T)/*后序遍历二叉树BT*/ {if(T==NULL)return;/*递归调用的结束条件*/ {Postorder(T->lchild);/*后序递归遍历左子树*/ Postorder(T->rchild);/*后序递归遍历右子树*/ printf(T->data);/*输出结点的数据域*/ } } 对于图9.10所示的二叉树,按后序遍历所得到的结点序列为: GDBEHFCA 例9.1 下列二叉树,如图9.13所示,求它的先序遍历、中序遍历、后序遍历和层次遍历序列。 图9.13 先序遍历的序列: ABDGEHCFIK 中序遍历的序列: DGBHEAFKIC 后序遍历的序列: GDHEBKIFCA 层次遍历的序列: ABCDEFGHIK 例9.2 设表达式A–B*(C+D)+E/(F+G)的二叉树表示如图9.14所示。 试写出它的先序遍历、中序遍历和后序遍历序列。 先序遍历的结果,即原表达式的前缀表达式: +–A*B+CD/E+FG 中序遍历的结果: A–B*C+D+E/F+G 后序遍历的结果,即原表达式的后缀表达式: ABCD+*–EFG+/+ 实训: 二叉树的建立和遍历 (先序建立二叉树,中序遍历之) #include"stdio.h" typedefstructbt {chardata; structbt*lchild; structbt*rchild; }BT; BT*CreatBiTree() { BT*t; charch; scanf("%c",&ch); if(ch=='') t=NULL; else {t=(BT*)malloc(sizeof(BT)); t->data=ch; t->lchild=CreatBiTree(); t->rchild=CreatBiTree(); } returnt; } voidInorder(BT*t) {if(t! =NULL) {Inorder(t->lchild); printf("%c",t->data); Inorder(t->rchild); } } voidmain() {BT*t; printf("先序建立二叉树: "); t=CreatBiTree(); printf("中序遍历该二叉树: "); Inorder(t); } 说明: 如图9.10所示的二叉树先序输入应为: ABDGCEFH 9.5 二叉查找树 9.5.1 二叉查找树的定义及其结构 二叉查找(搜索)树(BinarySearchTree)又称二叉排序树(BinarySortTree)。 其定义为: 二叉查找树或者是空树,或者是满足如下性质的二叉树: 若它的左子树非空,则左子树上所有结点的值均小于根结点的值; ②若它的右子树非空,则右子树上所有结点的值均大于根结点的值; ③左、右子树本身又各是一棵二叉排序树。 上述性质简称二叉排序树性质(BST性质),故二叉排序树实际上是满足BST性质的二叉树。 由BST性质可得: (1)二叉排序树中任一结点x,其左(右)子树中任一结点y(若存在)的关键字必小(大)于x的关键字。 (2)二叉排序树中,各结点关键字是惟一的。 (3)按中序遍历该树所得到的中序序列是一个递增有序序列。 9.6 堆排序 9.6.1 堆的定义 堆排序法是利用堆树(HeapTree)来进行排序的方法,堆树是一种特殊的二叉树,其具备以下特征: (1)是一棵完全二叉树。 (2)每一个结点的值均大于或等于它的两个子结点的值。 (3)树根的值是堆树中最大的。 如图9.16所示,图(a)是堆树,图(b)则不是。 (a)(b) 图9.16 堆排序的基本思想是,把用数组来存储待排序的数据转换成一棵完全二叉树,接着将完全二叉树转换成堆树后即可开始排序。 本章小结 树是一种以分支关系定义的层次结构,除根结点无直接前驱,其余每个结点有且仅有一个直接前驱,但树中所有结点都可以有多个直接后继。 树是一种具有一对多关系的非线性数据结构。 一棵非空的二叉树,每个结点至多只有两棵子树,分别称为左子树和右子树,且左右子树的次序不能任意交换。 它的左、右子树又分别都是二叉树。 若所有分支结点都存在左子树和右子树,且所有叶子结点都在同一层上,这样的一棵二叉树就是满二叉树。 若除最后一层外,若其余各层都是满的,并且最后一层或者为满,或者仅在右边缺少连续若干个结点,则称此二叉树为完全二叉树。 二叉树是本章的重点,必须重点掌握。 要求熟悉二叉树、满二叉树和完全二叉树之间的一些基本性质。 二叉树的遍历是指按某种顺序访问二叉树中的所有结点,使得每个结点都被访问,且仅被访问一次。 通过一次遍历,使二叉树中结点的非线性排列转变线性排列。 要求熟练掌握二叉树的前根遍历、中根遍历、后根遍历和层次遍历的概念和算法。 二叉树具有顺序存储和链式存储两种存储结构。 在顺序存储时,必须按完全二叉树格式存储;在二叉链式存储时,每个结点有两个指针域,具有n个结点的二叉树共有2n个指针,其中指向左、右孩子的指针有n-1个,空指针有n+1个。 本章的最后介绍了堆排序,其时间复杂度为O(nlog2n),且仅需一个记录大小供交换用的辅助空间。 实验十四二叉树的遍历 一、实验目的 1.掌握二叉树的特点及其存储的方式。 2.掌握二叉树的创建和显示方法。 3.复习二叉树遍历的概念,掌握二叉树遍历的基本方法 二、实验内容 题目按屏幕提示用前序方法建立一棵二叉树;编写前序遍历、中序遍历、后序遍历;编写求二叉树的叶结点数、总结点数和深度的程序;设计一个选择式菜单,以菜单方式选择下列操作。 二叉树子系统 ********************************************"); *1---------建二叉树*"); *2---------先序遍历*"); *3---------中序遍历*"); *4---------后序遍历*"); *5---------求叶子数*"); *6---------求结点数*"); *7-
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第9章