430 likes | 561 Views
第 5 章 树和二叉树. 5.1 树的基本定义 5.2 二叉树 5.3 树和森林 5.4 树的应用 5.5 应用举例分析. 本章要点. 树的各种术语 二叉树的性质、存储方式、遍历 树的存储、树和森林的转换、遍历 哈夫曼树和哈夫曼编码 线索二叉树的基本概念. 本章难点. 二叉树的性质、存储方式和遍历 哈夫曼树和哈夫曼编码 线索二叉树的基本概念. 学习目标. 掌握树的定义和各种术语 熟练掌握二叉树的基本操作 掌握哈夫曼树的操作与哈夫曼编码 熟悉线索二叉树的基本概念. 5.1 树的基本定义. 5.1.1 树的定义
E N D
第5章 树和二叉树 5.1 树的基本定义 5.2 二叉树 5.3 树和森林 5.4 树的应用 5.5 应用举例分析
本章要点 • 树的各种术语 • 二叉树的性质、存储方式、遍历 • 树的存储、树和森林的转换、遍历 • 哈夫曼树和哈夫曼编码 • 线索二叉树的基本概念
本章难点 • 二叉树的性质、存储方式和遍历 • 哈夫曼树和哈夫曼编码 • 线索二叉树的基本概念 学习目标 • 掌握树的定义和各种术语 • 熟练掌握二叉树的基本操作 • 掌握哈夫曼树的操作与哈夫曼编码 • 熟悉线索二叉树的基本概念
5.1 树的基本定义 • 5.1.1 树的定义 树(Tree)是n(n≥0)个有限数据元素的集合。当 n=0时,称这棵树为空树。在任意一棵非空树T中: (1)有且仅有一个特殊的数据元素称为树的根结 点,根结点没有前驱结点。 (2)若n>1,除根结点之外的其余数据元素被分成 m (m>0)个互不相交的集合T1,T2,… , Tm,其中每一个集合Ti (1≤i≤m)本身又是 一棵树。树T1,T2,… ,Tm称为这个根结 点的子树。
5.1 树的基本定义 • 5.1.2 基本术语 • 结点的度和树的度 树的结点包括一个数据元素及若干指向其子树的分支。结点拥有的子树个数称为结点的度(Degree)。树中所有结点的度的最大值为该树的度。 • 分支节点和叶子节点 度为0的结点称为叶子结点(Leaf)或终端结点。度不为0的结点称为非叶子结点或非终端结点。
5.1 树的基本定义 • 孩子结点、双亲结点和兄弟结点 结点子树的根称为该结点的孩子结点(Child),该结点是其孩子结点的双亲结点(Parent)。具有同一双亲结点的孩子结点之间互称为兄弟(Sibling)。某结点的祖先是指从根结点到该结点所经分支上的所有结点。以某结点为根的子树中的所有结点都称为该结点的子孙。
5.1 树的基本定义 • 结点的层数和树的深度 结点的层次(Level)从根开始算起,根为第一层,根的孩子为第二层,某结点所在的层从根开始向下计算。在树的同一层上而双亲结点不同的结点互为堂兄弟。树中结点的最大层次称为树的深度(Depth)或高度。 • 有序树和无序树 如果将树中结点的各个子树看成从左至右是有序的(即不能互换),则称该树为有序树,否则称为无序树。
5.1 树的基本定义 当用树来描述家谱时,应将树看成是有序树, 有序树中某结点最左边子树的根称为该结点的第 一个孩子,最右边子树的根称为最后一个孩子。 当用树来描述某单位的行政组织结构时,可将树 看成是无序树。 • 森林 森林(Forest)是m(m≥0)棵互不相交的树的集合,树和森林的概念很密切,删去一棵树的根,就得到一个森林。
5.2 二叉树 • 5.2.1 二叉树的定义和基本操作 • 1. 二叉树的基本概念 • 二叉树(Binary Tree)是n(n≥0)个结点的有限集合,当n=0时为空集,称为空二叉树;当n≠0时,二叉树由一个根结点及两棵互不相交、分别称为左子树和右子树的二叉树组成。二叉树和树在概念上相同的是都有一个且仅有一个根结点,根结点无前驱结点,叶子结点无后继结点。不相同的是二叉树中每个结点的度小于等于2,而且二叉树的子树有左右子树之分。
5.2 二叉树 • 2. 二叉树的基本操作 • 二叉树的基本操作通常有以下几种: • (1)INITIATE(BT) 建立一棵空二叉树。 • (2)CREATE(BT,LBT,RBT) 生成一棵以BT为根结点的数据域信息,以二叉树LBT和RBT为左子树和右子树的二叉树。 • (3)INSERTL(BT,X,PARENT) 将数据域信息为X的结点插入到二叉树BT中作为结点PARENT的左孩子结点。如果结点PARENT原来有左孩子结点,则将结点PARENT原来的左孩子结点作为结点X的左孩子结点。
5.2 二叉树 (4)INSERTR(BT,X,PARENT) 将数据域信息为X的结点插入到二叉树BT中作为结点PARENT的右孩子结点。如果结点PARENT原来有右孩子结点,则将结点PARENT原来的右孩子结点作为结点X的右孩子结点。 (5)TREEDEPTH(BT) 求二叉树的深度。返回二叉树BT的深度。 (6)DELETEL(BT,PARENT) 在二叉树BT中删除结点PARENT的左子树。 (7)DELETER(BT,PARENT) 在二叉树BT中删除结点PARENT的右子树。 (8)SEARCH(BT,X) 在二叉树BT中查找数据元素X。
5.2 二叉树 • 5.2.2 二叉树的性质 • 性质1二叉树第i层上的结点数目至多为 2i-1(i≥1)。 • 性质2深度为k的二叉树至多有2k-1个结点 (k≥1)。 • 性质3 在任何一棵二叉树中,如果其终端 结点数为n0,度为2的结点数为n2, 则n0=n2+1
5.2 二叉树 • 性质4具有n个结点的完全二叉树的深度为。 • 性质5对一棵有n个结点的完全二叉树的结点按层自 左向右编号,则对任一编号为i(1≤i≤n)的结 点有下列性质: • (1)若i=1,则结点i是二叉树的根,若i>1,则结 点i的双亲结点是; • (2)若2i≤n,则结点i有左孩子,左孩子的编号 是2i,否则结点i无左孩子,并且是叶子结点; • (3)若2i+1≤n,则结点i有右孩子,右孩子的编号 是2i+1,否则结点i无右孩子。
5.2 二叉树 • 性质6对一棵有n个结点的完全二叉树的结点按层自左向右编号,从编号为1的根结点开始到编号为的结点为止,都是有孩子结点的非叶子结点,余后的结点均是叶子结点。编号的结点可能只有左孩子结点,可能是既有左孩子结点又有右孩子结点。 • 5.2.3 二叉树的存储结构 • 1. 顺序存储结构 • 顺序存储就是用一组地址连续的存储单元来存放一棵二叉树的结点。一般是按照二叉树结点从上至下、从左到右的顺序存储。
5.2 二叉树 • 2. 链式存储结构 • 所谓二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。通常有下面两种形式。 • (1)二叉链表存储 • 链表中每个结点由三个域组成,除了数据域外,还有两个指针域,分别用来给出该结点左孩子和右孩子所在的链结点的存储地址。
5.2 二叉树 其中,data域存放某结点的数据信息;lchild与rchild分别存放指向左孩子和右孩子的指针,当左孩子或右孩子不存在时,相应指针域值为空(用符号∧或NULL表示)。 • (2)三叉链表存储 其中,data、lchild以及rchild三个域的意义同二叉链表结构;parent域为指向该结点双亲结点的指针。这种存储结构既便于查找孩子结点,又便于查找双亲结点;但是,相对于二叉链表存储结构而言,它增加了空间开销。
5.2 二叉树 • 5.2.4 二叉树的遍历 • 1. 二叉树的遍历方法及递归实现 • (1)先序遍历二叉树 • 若二叉树非空,则依次进行如下操作: • ① 访问根结点; • ② 先序遍历左子树; • ③ 先序遍历右子树。
5.2 二叉树 • (2)中序遍历二叉树 • 若二叉树非空,则依次进行如下操作: • ① 中序遍历左子树; • ② 访问根结点; • ③ 中序遍历右子树。
5.2 二叉树 • (3)后序遍历二叉树 • 若二叉树非空,则依次进行如下操作: • ① 后序遍历左子树; • ② 后序遍历右子树; • ③ 访问根结点。
5.2 二叉树 • 2. 二叉树遍历的非递归实现 • 对于非递归算法,引入栈模拟递归形式,初始时栈为空。 • (1)先序遍历的非递归实现 • 思路:访问bt->data后,将bt入栈,遍历左子树;遍历完左子树返回时,栈顶元素应为bt,出栈,再先序遍历bt的右子树。
5.2 二叉树 • (2)中序遍历非递归实现 • 思路:先将bt入栈,遍历左子树;遍历完左子树返回时,栈顶元素应为bt,出栈,访问bt->data,再中序遍历bt的右子树。 • (3)后序遍历非递归实现 • 思路:可采用标记法,结点入栈时,配一个标志tag一同入栈(0:遍历左子树前的现场保护,1:遍历右子树前的现场保护)。首先将T和tag(为0)入栈,遍历左子树;返回后,修改栈顶tag为1,遍历右子树;最后访问根结点。
5.2 二叉树 • (4)层次遍历二叉树 • 所谓二叉树的层次遍历,是指从二叉树的第一层(根结点)开始,从上至下逐层遍历,在同一层中,则按从左到右的顺序对结点逐个访问。由层次遍历的定义可以推知,在进行层次遍历时,对一层结点访问完后,再按照它们的访问次序对各个结点的左孩子和右孩子顺序访问,这样一层一层进行,先遇到的结点先访问,这与队列的操作原则比较吻合。
5.2 二叉树 • 因此,在进行层次遍历时,可设置一个队列结构,遍历从二叉树的根结点开始,首先将根结点指针入队列,然后从队头取出一个元素,每取一个元素,执行下面两个操作: • ① 访问该元素所指结点; • ② 若该元素所指结点的左、右孩子结点非空,则将该元素所指结点的左孩子指针和右孩子指针顺序入队。 • 此过程不断进行,当队列为空时,二叉树的层次遍历结束。
5.3 树和森林 • 5.3.1 树的存储结构 • 1. 双亲表示法 • 设以一组地址连续的空间存放树的结点,每个结点中除了存放结点的信息外,增设一个整型指针域,指示其双亲结点所在的位置序号。这样的存储结构称之为静态链表结构。这样的静态链表可反映出一棵树中结点之间的逻辑关系,即可惟一地表示一棵树,称之为双亲表示法。
5.3 树和森林 • 2. 孩子表示法 • 孩子表示法是把每个结点的孩子结点链接形成单链表,n个结点有n个孩子链表(叶子结点的孩子链表为空)。n个结点的信息和指向孩子链表的指针作为表头结点组成一个表头向量,采用顺序存储结构。与双亲表示法相反,孩子表示法便于查找树中某结点的孩子,由表中某结点的指针域headptr即可得到该结点的孩子结点。
5.3 树和森林 • 3. 孩子兄弟表示法 • 孩子兄弟表示法又称二叉树表示法,即以二叉链表作为树的存储结构。链表中每个结点的结构相同,都有三个域:数据域存放树中结点的信息,孩子域存放该结点的第一个孩子结点(从左算起)的地址,兄弟域存放该结点的下一个兄弟结点(从左向右)的地址。 • 5.3.2 树、森林、二叉树的转换 • 1. 树转换成二叉树
5.3 树和森林 • 将一棵树转换为二叉树的方法是: • (1)树中所有相邻兄弟之间加一条连线。 • (2)对树中的每个结点,只保留它与第一个孩子 结点之间的连线,删去它与其它孩子结点之 间的连线。 • (3)以树的根结点为轴心,将整棵树顺时针转动 450,使之结构层次分明。
5.3 树和森林 • 2. 森林转换成二叉树 • 对于森林F中的每一棵树Ti,树根结点下的若干棵子树可看成是树根结点下的子树森林;对于二叉树B,根结点下的左右子树LB,RB仍是一棵二叉树。 • 如果F={T1,T2, … , Tm}是森林,按如下规则可转换成一棵二叉树B=(root,LB,RB)。 • (1)若F为空,则B为空; • (2)若F非空,则森林中第一棵树T1的根结点为二叉树B的根结点,B的左子树LB由树T1根结点下的子树森林转换而成。右子树RB是由森林F中除树T1外余下部分转换而成。
5.3 树和森林 • 3. 二叉树转换成森林 • 如果B=(root,LB,RB)是一棵二叉树,按如下规则转换成森林F={T1,T2, … , Tm}。 • (1)若B为空,则F为空; • (2)若B非空,则二叉树B的根root为森林F中第一棵树T1的根,树T1的根结点的子树森林是由B的左子树LB转换而成,F中其余的树由B的右子树RB转换而成。
5.3 树和森林 • 5.3.3 树和森林的遍历 • 1. 先序遍历 • 若森林非空,则 • (1)访问森林中第一棵树的根结点; • (2)先序遍历第一棵树根结点的各子树森林; • (3)先序遍历森林中除第一棵树外剩余的树构成的森林。
5.3 树和森林 • 2. 后序遍历 • 若森林非空,则 (1)后序遍历第一棵树的根结点的各子树森林; (2)访问森林中第一棵树的根结点; (3)后序遍历森林中除第一棵树外剩余的树构成的森林。 • 3. 按层次遍历 • 若森林非空,则 (1)对第一棵树从根结点起按层从左到右依次访问结点; (2)按层访问森林中除第一棵树外剩余的树构成的森林。
5.4 树的应用 • 5.4.1 哈夫曼树和哈夫曼编码 • 1. 哈夫曼树的定义及构造方法 • 哈夫曼树(Huffman),又称最优二叉树。 • 首先给出路径和路径长度的概念。从树中一个结点到另一个结点之间的分支就构成这两个结点之间的路径,路径上的分支数目称为两个结点之间的路径长度。树的路径长度是从该树的根到每一结点的路径长度之和。
5.4 树的应用 • 在许多应用中,树中结点常常带权,权值是具有某种含义的实数,称为该结点的权。结点的带权路径长度是该结点到树根之间的路径长度与结点的权的乘积。树的带权路径长度(Weighted Path Length of Tree)定义为树中所有叶子结点的带权路径长度之和,记为 • WPL= • 其中,n表示叶子结点的数目; Wi和Li分别表示第i个叶子结点的权值和树根到该叶子结点之间的路径长度。
5.4 树的应用 • 假设有n个权值(w1,w2,w3,…,wn),欲构造一棵有n个叶子结点的二叉树,每个叶子结点带权为wi,则这样的二叉树可以有若干棵,如图5-19中的三棵二叉树,它们都有4个叶子结点A, B, C, D,且分别带权7, 5, 2, 4,三棵二叉树的带权路径长度分别为36,46,35。
5.4 树的应用 图5-19 具有不同带权路径长度的二叉树
5.4 树的应用 • 2. 哈夫曼编码 • 在电报的运作过程中,传送的电文以二进制代码作为电报编码。即电报发出方需将电文转换成二进制编码发出,而接收方又将接收到的一串二进制码按编码原则翻译成原电文。例如,传送的电文为“ABAACCBADCA”,电文中只含有四个字符,每个字符用二个bit作为定长编码即可发送电文和接收电文。假设A,B,C,D的二进制编码分别为00,01,10,11,则上述电文的译文为“0001000010100100111000”,总长为22个bit。对方接收时,按二位一组进行译码即可。
5.4 树的应用 • 5.4.2 线索二叉树 • 1. 线索二叉树的定义及结构 • (1)线索二叉树的定义 • 可以把二叉树中除第一个结点外,每个结点有且仅有一个直接前驱结点;除最后一个结点外,每个结点有且仅有一个直接后继结点。为了保留结点在某种遍历序列中直接前驱和直接后继的位置信息,可以利用二叉树的二叉链表存储结构中的那些空指针域来指示。这些指向直接前驱结点和指向直接后继结点的指针被称为线索(thread),加了线索的二叉树称为线索二叉树。
5.4 树的应用 • (2)线索二叉树的结构 • 一个具有n个结点的二叉树若采用二叉链表存储结构,在2n个指针域中只有n-1个指针域是用来存储结点孩子的地址,而另外n+1个指针域存放的都是NULL。因此,可以利用某结点空的左指针域(lchild)指出该结点在某种遍历序列中的直接前驱结点的存储地址,利用结点空的右指针域(rchild)指出该结点在某种遍历序列中的直接后继结点的存储地址;对于那些非空的指针域,则仍然存放指向该结点左、右孩子的指针。这样,就得到了一棵线索二叉树。
5.4 树的应用 • 2. 线索二叉树的基本操作 • (1)建立一棵中序线索二叉树 • (2)在中序线索二叉树上查找任意结点的中序前驱结点 • (3)在中序线索二叉树上查找任意结点的中序后继结点 • (4)在中序线索二叉树上查找任意结点在先序下的后继 • (5)在中序线索二叉树上查找任意结点在后序下的前驱 • (6)在中序线索二叉树上查找值为x的结点
本章小结 • 树是数据结构的重点章节,而其中的二叉树又是本章的重点内容。在这一章里要了解树的定义熟悉二叉树的定义、性质、存储结构、遍历、线索化和树的存储结构、遍历以及树、森林与二叉树的转换,哈夫曼树及哈夫曼编码等内容。算法的重点是二叉树的遍历及其有关应用。这也是本章的难点。 • 1. 树的各种术语:如结点的度和树的度,分支节点和叶子节点,孩子结点、双亲结点和兄弟结点,结点的层数和树的深度,有序树和无序树,森林等。
本章小结 • 2. 二叉树的性质、存储方式、遍历:要求熟练掌握二叉树的性质,二叉树的顺序存储结构就是把二叉树的所有结点按照一定次序(从根结点起,从上层到下层,从左往右编号就得到了存放的次序)存储到一片连续的存储单元中 。用顺序存储方式对于完全二叉树而言其结构简单又节省空间,但是对于一般二叉树并不合适。因此树的存储结构更多的是用链式存储。结点的结构为两个指针域lchild和rchild分别指向该结点的左孩子和右孩子,另有一个数据域data存放结点数据。根据访问结点的次序不同可得三种遍历:先序遍历(前序遍历或先根遍历),中序遍历(或中根遍历)、后序遍历(或后根遍历)。
本章小结 • 3. 树的存储、树和森林的转换、遍历:树的存储结构:有双亲链表表示法,孩子链表表示法和孩子兄弟链表表示法。树和森林及二叉树的转换:三者是惟一对应的,它们之间的转换办法应掌握。树和森林因为每个结点有两棵以上的子树,因此不便于讨论中根次序遍历,但是其前序遍历和后序遍历还是应该了解的。
本章小结 • 4. 哈夫曼树和哈夫曼编码:哈夫曼树(Huffman),又称最优二叉树。哈夫曼树的应用最广泛地是在编码技术上,它能够容易地求出给定字符集及其概率分布的最优前缀码。(最优前缀码就是平均码长最小的前缀码)。哈夫曼编码的构造很容易,只要构造好了哈夫曼树,按分支情况在左路径上写代码0,右路径上写代码1,然后从上到下到叶结点的相应路径上的代码的序列就是该结点的最优前缀码。 • 5. 线索二叉树的基本概念:为了保留结点在某种遍历序列中直接前驱和直接后继的位置信息,可以利用二叉树的二叉链表存储结构中的那些空指针域来指示。这些指向直接前驱结点和指向直接后继结点的指针被称为线索(thread),加了线索的二叉树称为线索二叉树。