收藏 分享(赏)

数据结构第6章.ppt

上传人:hwpkd79526 文档编号:8269964 上传时间:2019-06-17 格式:PPT 页数:73 大小:474.50KB
下载 相关 举报
数据结构第6章.ppt_第1页
第1页 / 共73页
数据结构第6章.ppt_第2页
第2页 / 共73页
数据结构第6章.ppt_第3页
第3页 / 共73页
数据结构第6章.ppt_第4页
第4页 / 共73页
数据结构第6章.ppt_第5页
第5页 / 共73页
点击查看更多>>
资源描述

1、第6章 树形结构,6.1 树形结构的基本概念 6.2 二叉树的基本概念和性质 6.3 二叉树的存储结构 6.5 二叉树的遍历 6.8 树与森林 6.10 树的应用示例哈夫曼树,6.1.1 树结构的定义,数据对象 D: n个数据元素的有穷集合(n0) 数据关系R: n=0时,称为空树;n0时,它满足以下条件: (1)有且仅有一个结点d0D,满足:不存在任何dD,使R。我们称它为树的根(Root)。 (2) 除根结点d0外,D上每个结点d(若有的话),总存在一个唯一的结点dD,dd,使得R。 (3)若T-d0非空,则T-d0可分成m个(m0)不相交的集合T1,T2,.,Tm,而且这些集合中的每一个

2、又都是满足本定义的树,称作T的子树(subTree)。若T-d0为空,称T无子树(或子树为空)。(递归定义),6.1 树结构的基本概念,树形结构示例及相关术语,A,B,C,D,E,F,G,I,J,Level 1,Level 2,Level 3,Level 4,Depth= 4,A,(b),(c),(a),分支(Branch):结点之间的二元关系。 入度(In Degree):x的前驱的个数称为x的入度。 结点(Node):数据元素若干个指向子树的分支。 度(Degree)/出度(Out Degree):结点拥有的子树(后继)的个数称为该结点的度,也称为出度。 树的度:树中所有结点的度的最大值

3、叶子结点(Leaf Node):无后继(子树)的结点称为叶子。 分支结点(Branch Node):有后继的结点称为分枝结点。 层次(Level):根为第1层,对任何其它结点,若它父亲为第k层结点,则它为第(k+1)层结点(层号为k+1)。儿子结点(Sons) ;双亲(父亲)(Parents);祖先(Ancestor); 后代(Descendants);兄弟(Brothers);堂兄弟(Cousin) ;,深度(depth):树中的具有最大层号的结点的层号,称为树的深度/高度。祖辈(上层)(Forerunner):层号比结点x小的结点,称为x的祖辈(上层)后辈(下层)(Latecomes):层

4、号比结点x大的结点,称为x的后辈(下层),森林(Forest):相互m(m0)不相交的树的集合称为森林。反过来树也可以有森林来定义:任何一棵非空树是一个二元组 Tree = (root, F) root为根结点,F为子树森林 有序树: 子树的次序不能互换 无序树: 子树的次序可以互换,线性结构与树形结构比较,线性结构 第一个数据元素 (无前驱) 最后一个数据元素(无后继) 其它数据元素 (一个前驱、一个后继),树形结构 根结点(无前驱) 多个叶子结点(无后继) 其它结点 (一个前驱、多个后继),6.2 二叉树的概念,该集合或者为空,或者是由一个根结点加上两棵分别称为左子树和右子树的、互不相交的

5、二叉树组成。,左子树,右子树,左子树,右子树,(a) (b) (c) (d) (e)五种二叉树的基本形态,6.2.2 几种特殊二叉树,下面介绍几种特殊结构的二叉树,它们在实际中有许多应用。这几种特殊二叉树是逻辑结构上的特殊二叉树,在后面的章节中,我们还将介绍几种语义上的特殊二叉树。,(1) 满二叉树. 只含度为0与度为2的结点,且度为0的结点只出现在最后一层的二叉树称为满二叉树。实例见图 63 (a). (2)顺序二叉树(?)对任一棵满二叉树,从它的最后一层的最右结点起,按从下到上、从右到左的次序,去掉若干个结点后所成的树称为顺序二叉树。实例见图 63 (b). (3)完全二叉树(?) 不含度

6、为1的结点的二叉树称完全二叉树。 显然,与满二叉树的不同是,完全二叉树的度为0的结点可出现在任一层上。实例见图 63 (c)(d)。 (4)平衡二叉树 若树中任一结点的任两个子树的高度之差不超过1,则称这种树为平衡树,特别是对二叉树,则为平衡二叉树。实例见图 63 (f)。,(a) 满二叉树,(b) 顺序二叉树,(d) 顺序、完全二叉树,(e) 平衡二叉树,(f) 一般二叉树(非平衡),(c) 完全二叉树,图 63 特殊二叉树示例,定理6-1 若二叉树的层次从1开始, 则在二叉树的第 i 层最多有 2i-1 个结点。(i 0),证明:i = 1 时,有2i-1 = 20 =1,成立 假定 :i

7、 = k 时性质成立; 当 i = k+1 时,第k+1的结点至多是第k层结点的两倍,即总的结点个数至多为22k-1 = 2k 故命题成立 (合并了书中的定理6-1和6-2),6.2.3 二叉树的基本性质,定理6-3 高度为k的二叉树最多有 2k-1个结点。(k 1),证明:仅当每一层都含有最大结点数时,二叉树 的结点数最多,利用性质1可得二叉树的结点数 至多为: 20 + 21 + 22 + 23 + + 2k-1 = 2k 1 合并书中定理6-3和6-4,定理 65:对任一棵二叉树,有 n0=n2+1 n=2n0+n1-1 这里,n0、n1和n2分别为度为0、1和2的结点的数目,n表示结点

8、总数。 证:显然,n=n0+n1+n2 另一方面,由于二叉树除根外每个结点恰好有一个前趋,所以,非根结点恰与分枝一一对应,故有 n=B+1 这里,B为分枝数目。又分枝是由度为1和2的结点射出的,故有 B=n1+2n2 结合上面三式,即可导出n0=n2+1与n=2n0+n1-1,定理6-6 具有n个结点的顺序二叉树(?)的高度为 log2n +1,!在其他书籍,此定理中的顺序二叉树为完全二叉树,定理 67:若对一棵顺序二叉树的结点按层序编号(即从根所在层起,依次从层号较小的层到层号较大的层、同层从左到右,给各结点依次编以连续的号码),则对任一结点i(1in,n为结点数目,1为根的编号),有 (a

9、)若i=1,则结点i是根,无父亲,若i1,则其父亲的编号为i/2; (b)若2in,则结点i无左儿子(从而也无右儿,为叶子),否则i的左儿子的编号为2i。 (c)若2i+1n,则结点i无右孩子,否则它的右孩子结点的编号为2i+1。,6.2.4 二叉树的遍历的概念,遍历:顺着某一条搜索路径巡防二叉树中的结点,使得每个结点均被访问一次,而且仅被访问一次。 “访问”的含义很广泛。如:输出结点中的信息等。 “遍历”是任何类型数据结构均有的操作,对线性结构而言,只有一条搜索路径(因为每个结点只有一个后继),故不需要特别地讨论。而二叉树的每个结点可能有两个后继,则存在选择何种路径来遍历所有结点的问题。,搜

10、索路径,对“二叉树”而言,有三条搜索路径: 1. 现上后下的按层次遍历 2. 先左(子树)后右(子树)的遍历 3. 先右(子树)后左(子树)的遍历,先左后右的遍历算法,先(根)序遍历 中(根)序遍历 后(根)序遍历 按层次遍历 层序遍历,前序遍历,前序遍历二叉树算法: 若二叉树为空,则空操作; 否则 访问根结点 (V); 前序遍历左子树 (L); 前序遍历右子树 (R)。,前序遍历结果:1 2 4 5 3 6 7 中序遍历结果:2 5 4 1 3 7 6 后序遍历结果:5 4 2 7 6 3 1 层序遍历结果:1 2 3 4 6 5 7,图6 0 二叉树遍历示例,中序遍历二叉树算法: 若二叉树

11、为空,则空操作; 否则 中序遍历左子树 (L); 访问根结点 (V); 中序遍历右子树 (R),后序遍历二叉树算法: 若二叉树为空,则空操作; 否则 后序遍历左子树 (L); 后序遍历右子树 (R); 访问根结点 (V)。,二叉树遍历,前序、中序和后序遍历都是采用递归的方式定义和实现,层序遍历 层序遍历是按树的层序编号的次序访问各结点,即按从上层到下层,同层内从左到右的次序访问结点。,层序遍历二叉树算法是 若二叉树为空,则空操作; 否则,根结点进队如队列不空,循环:将队首结点的左右孩子入队;队首出队; 最后,出队序列就是层序遍历序结果,6.3二叉树的存储结构,6.3.1顺序存储结构,顺序二叉树

12、的顺序存储结构这种存储结构是按结点的层序编号的次序,将结点存储在一片连续存储区域内。结点的相对地址与编号之间的换算,有下列关系: 结点相对地址 = (结点编号 1)每个结点所占单元数目,A,C,B,1,2,4,3,5,7,6,8,9,10,数组下标 0 1 2 3 4 5 6 7 8 9,一般二叉树的顺序存储 对一般的二叉树而言,则需在该二叉树中补设一些虚结点,使它成为一棵顺序二叉树,然后对结点按层序编号。 这种存储方式中,实结点是不连续出现的,所以,若虚结点对应的存储位置不能被利用,则是一种很大的浪费(虚结点数目可能很大),a,b,c,1 2 3 4 5 6 7 9 ,a x b x x x

13、 c ,图 一般二叉树的连续存储(x表示虚结点的位置),6.3.2 链式存储,所谓二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示着元素的逻辑关系。常用的两种形式 。 二叉表(二指针式) 三叉表(三指针式),二叉表,结点的存储的结构为,(a) 带头指针的二叉链表 (b) 带头结点的二叉链表,三叉表,结点的存储的结构为,三叉链表表示示意图,6.4 二叉树对象模型,二叉树的存储结构是:二叉表 二叉树的基本操作: 1.创建二叉树 2.二叉树的遍历(前序遍历、中序遍历、后序遍历和层序遍历) 3. 删除二叉树,二叉树的对象描述,template class TBinTree public:

14、TBinTreeNode* root;long numNodes;TBinTree();TBinTree();virtual void preCreateBinTree(TBinTreeNode* r);virtual void preTraverse(TBinTreeNode* r);virtual void preTraverse_stack(TBinTreeNode* r);virtual void inTraverse(TBinTreeNode* r);virtual void postTraverse(TBinTreeNode* r);virtual void levelTraver

15、se(TBinTreeNode* r);virtual void delBinTree(TBinTreeNode* r); ;,template struct TBinTreeNodeTBinTreeNode *lchild, *rchild;TElem data;,二叉树初始化和终止,template TBinTree:TBinTree() root = NULL;numNodes=0; template TBinTree:TBinTree() if (root) cout “nDelte this BiTree in desConstruct function.n“;delBinTree(

16、root); ,创建二叉树,template void TBinTree:preCreateBinTree(TBinTreeNode* r)TElem ch;cin ch;if(ch = ) *r = NULL;elseif(!(*r)=(TBinTreeNode*) malloc(sizeof(TBinTree) exit (-1);if(root = NULL) root = *r;numNodes+;(*r)-data = ch;preCreateBinTree( ,二叉树前序遍历,template void TBinTree:preTraverse(TBinTreeNode* r)if

17、(r)cout data lchild);preTraverse(r-rchild); ,二叉树中序遍历,template void TBinTree:inTraverse(TBinTreeNode* r)if(r)inTraverse(r-lchild);cout data rchild); ,二叉树后序遍历,template void TBinTree:postTraverse(TBinTreeNode* r)if(r)postTraverse(r-lchild);postTraverse(r-rchild);cout data “ “; ,递归算法的跟踪,以如下二叉树为例,用T(x)表示

18、遍历算法,它表示遍历以x为根的子树,用P(x)表示输出/访问结点x。方框中左边括号中的数字表示子程序调用序号。,图 6 一棵二叉数,二叉树的前序遍历递归算法执行过程,二叉树前序遍历(堆栈实现),template void TBinTree:preTraverse_stack(TBinTreeNode* r)TStackSqu* preStack(50); TBinTreeNode* ptr;ptr = r;if(ptr= NULL) return;cout data lchild)cout lchild-data lchild);ptr=ptr-lchild;elseptr = preStac

19、k.Pop();if(ptr-rchild)cout rchild-data rchild);ptr=ptr-rchild;while(!preStack.IsEmpty(); ,二叉树层序遍历,template void TBinTree:levelTraverse(TBinTreeNode* r)TQueueLink* levelQ; TBinTreeNode* ptr;if(r) levelQ.QPush(r);while(!levelQ.IsEmpty()ptr = (TBinTreeNode*) levelQ.QPop();cout data lchild) levelQ.QPush

20、(ptr-lchild);if(ptr-rchild) levelQ.QPush(ptr-rchild); ,删除二叉树,template void TBinTree:delBinTree(TBinTreeNode* r)if(r)delBinTree(r-lchild);delBinTree(r-rchild);delete r; ,二叉树遍历的应用,统计二叉树叶子结点的个数(先序遍历)template void TBinTree:countLeaf(TBinTreeNode* r, int ,二叉树遍历的应用,template int TBinTree:depthBitree(TBinTr

21、eeNode* r)int depthval, depthLeft, depthRight;if(!r)depthval =0;elsedepthLeft = depthBitree(r-lchild);depthRight = depthBitree(r-rchild);depthval = 1 + (depthLeftdepthRight ?depthLeft:depthRight);return depthval; ,求二叉树的深度(后序遍历),6.8 树与森林,前面已给出树与森林的概念,但只是重点介绍了二叉树,本节开始讨论树与森林操作、存储及其与二叉树的转化等问题。,树的存储结构,树的

22、存储有多种方式,既可以采用顺序存储结构,也可以采用链式存储结构,但无论采用何种存储方式,都要求存储结构不但能存储各结点本身的数据信息,还要能唯一地反映树中各结点之间的逻辑关系。 双亲表示法 孩子链表表示法 孩子兄弟表示法,树的示例图,双亲表示法,#define MAXNODE template struct TTreeNodeP TElem data;int parent; struct TTreeNodePtMAXNODE;,序号 data parent,邻接表法,#define MAXNODE /链结点定义 template struct TTreeLinkNodelong childNo

23、deId;struct TTreeLinkNode *nextchild;/树结点定义 template struct TTreeNodeAdjTElem data;struct TTreeLinkNode *firstchild;long fatherId;long numsons; struct TTreeNodeAdj tMAXNODE;,序号 data parent,1,5,4,8,7,6,3,2,孩子兄弟表示法,template struct TreeNodeBinLink TElem data; struct TreeNodeBinLink *firstson; struct Tr

24、eeNodeBinLink *nextBrother; ;,树/森林与二叉树之间的转化,与树相比,二叉树的存储与操作实现要简单一些。若能将树确定地转化为二叉树,并可确定地将转化后的结果还原为原树,则对树的处理就转化为对二叉树的处理了。,树转换为二叉树的方法,将一棵树转换为二叉树的方法是: (1) 树中所有相邻兄弟之间加一条连线。 (2) 对树中的每个结点,只保留它与第一个孩子结点之间的连线,删去它与其它孩子结点之间的连线。 (3) 以树的根结点为轴心,将整棵树顺时针转动一定的角度,使之结构层次分明。,树转换为二叉树示例,森林转化为二叉树的方法,(1) 若F为空,即m0,则B为空树; (2) 若

25、F非空,即m0,则B的根root即为森林中第一棵树的根Root(T1);B的左子树LB是从T1中根结点的子树森林F1 T11,T12,T1m1 转换而成的二叉树;其右子树RB是从森林F T2,T3,Tm 转换而成的二叉树。,森林转化为二叉树示例,树与森林的遍历,(一) 树的遍历由于树不象二叉树那样,根位于二棵子树的中间,故一般无“中序”一说。树一般只有先根和后根及层序三种遍历方法。关于层序遍历,与二叉树相同。,1先根遍历先根遍历以root为根的树(子树)的规则为: 若root为空,则无动作,结束; 若root不空,则先访问根结点,然后按此规则(先根),按各子树的次序(若为无序树,则次序任意)分

26、别遍历root的各子树。2后根遍历后根遍历以root为根的树(子树)的规则为: 若root为空,则无动作,结束;若root不空,则按后根遍历规则,按各子树的次序(若为无序树,则次序任意)分别遍历root的各子树,然后访问根。,例 66 对图所示树的遍历结果为: 先根: A B E F C D G后根: E F B C G D A,树的先根遍历与其转换的相应二叉树的先序遍历的结果序列相同;树的后根遍历与其转换的相应二叉树的中序遍历的结果序列相同。因此树的遍历算法是可以采用相应二叉树的遍历算法来实现的。,(二) 森林的遍历森林可有三种遍历方式:前序遍历、后序遍历 及层序遍历。层序遍历与二叉树相同。

27、1前序遍历 若森林为空,则无动作,返回。 若森林非空,则 先访问森林中的第1棵子树的根结点;前序遍历第1棵子树的根的各子树构成的森林;前序遍历除去第1棵子树后剩余子树构成的森林。,2后序遍历/中序遍历 若森林为空,则无动作,返回。 若森林不空,则后序遍历森林中第1棵子树的根结点的各子树构成的森林。访问第1棵子树的根。后序遍历除去第1棵子树后剩余子树构成的森林。,例 67 对图所示森林的遍历结果为: 前序:A B C D E F G H J I K 后/中序:B A D E F C J H K I G,森林的前序遍历和中序遍历与所转换的二叉树的先序遍历和中序遍历的结果序列相同。,6.10 树的应

28、用示例哈夫曼树,最优树的定义 如何构造最优树 前缀编码,最优树的定义,结点的路径长度:从根结点到该结点的路径上分支的数目 树的路径长度:树中每个结点的路径长度之和。 树的带权路径长度:树中所有叶子结点的带权路径长度之和。,其中Wi为第i个叶结点的权值,Pi 为第i个叶结点的路径长度。,在所有含n个叶子结点,并带相同权值的m叉树中,必存在一棵带权路径长度最小的树,其被称为“最优树”。,带权路径长度示例,(a) (b) (c),这三棵树的带权路径长度分别为: (a)WPL1232527232 (b)WPL1333527129 (c)WPL7353321143,要使二叉树的WPL值最小,必须使权值越

29、大的叶结点越靠近根结点,而权值越小的叶结点越远离根结点。,哈夫曼树(最优树)构造算法,我们假定已知n个权值W=w1, w2, , wn,构造一棵具有n个叶子且叶子权分别对应这n个值的哈夫曼树。具体步骤如下。1.初试化 构造一个森林F=w1, w2, , wn,它有n棵树,每棵树只有一个结点,且其权分别为给定的n个权值。2.找最小树 从F中找两棵根权最小的树,分别以它们为左右子树,构造一棵新树,并令新树的根的权为这两棵根权之和。3.删除 从F中将所找到的两棵最小树删除4.加入 将新构造的树加入F.5.判断 若F中只剩一棵树,则结束,其即为所求,否则,转2。,例 68 设W=2,3,5,6,7,

30、则构造对应的哈夫曼树 的过程如图所示.,哈夫曼树构造算法的实现,数据结构的存储考虑哈夫曼树是一种二叉树,其当然可采用前面给出的存储方法。这里采用一维数组存储哈夫曼树的方法。 各结点存储在一维数组中。0号位置不使用,从1号位置起存储。设哈夫曼树有n个叶子,则由前面的定理知,其结点总数为2n-1. 每个结点的结构为 (权值,父亲序号,左儿子序号,右儿序号)叶子集中存储在前面部分,即1n的位置,而(n+1)(2n-1)存储其余结点。用0表示空指针。,程序实现,哈夫曼编码基本概念,在数据通讯中,经常需要将传送的文字转换成由二进制字符0,1组成的二进制串,我们称之为编码。传送电文时,我们总是希望传送时间

31、尽可能短,这就要求电文代码尽可能短。 等长编码:每个字符采用相同位数的编码方式。 不等长编码:如果在编码时考虑字符出现的频率,让出现频率高的字符采用尽可能短的编码,出现频率低的字符采用稍长的编码,构造一种不等长编码,则电文的代码就可能更短。 在建立不等长编码时,必须使任何一个字符的编码都不是另一个字符编码的前缀,这样才能保证译码的唯一性。,例如,假设要传送的电文为ABACCDA 。 编码A电文的代码为00010010101100,长度为14。 编码B电文的代码为0110010101110,长度为13 。 编码C电文的代码为001011100,长度为9,前缀码:如果在一个编码系统中,任一个编码都

32、不是其他任何编码的前缀,则称该编码系统是前缀码。,哈夫曼编码,哈夫曼编码:利用哈夫曼树构造出来的编码。特点是编码的总长度最短,并且是前缀码。具体做法如下:设需要编码的字符集合为d1,d2,dn,它们在电文中出现的次数或频率集合为w1,w2,wn,以d1,d2,dn作为叶结点,w1,w2,wn作为它们的权值,构造一棵哈夫曼树,规定哈夫曼树中的左分支代表0,右分支代表1,则从根结点到每个叶结点所经过的路径分支组成的0和1的序列便为该结点对应字符的编码,我们称之为哈夫曼编码。 总编码长度正好等于霍夫曼树的带权路径长度WPL。,设给出一段报文: CAST CAST SAT AT A TASA字符集合是

33、 C, A, S, T ,各个字符出现的频度(次数)是 W 2, 7, 4, 5 。若给每个字符以等长编码A : 00 T : 10 C : 01 S : 11 则总编码长度为 ( 2+7+4+5 ) * 2 = 36.若按各个字符出现的概率不同而给予不等长编码,可望减少总编码长度。因各字符出现的概率为 2/18, 7/18, 4/18, 5/18 。 化整为 2, 7, 4, 5 ,以它们为各叶结点上的权值,建立霍夫曼树。左分支赋 0,右分支赋 1,得霍夫曼编码(变长编码)。 A : 0 T : 10 C : 110 S : 111 它的总编码长度:7*1+5*2+( 2+4 )*3 = 35。比等长编码的情形要短。,哈夫曼编码的程序实现,熟练掌握二叉树的结构特性,了解相应的证明方法。 熟悉二叉树的各种存储结构的特点及适用范围。 遍历二叉树是二叉树各种操作的基础。实现二叉树遍历的具体算法与采用的存储结构有关。掌握各种遍历策略的递归和非递归算法,灵活运用遍历算法实现二叉树的其他操作。 层次遍历是按另一种搜索策略进行的遍历。 掌握树和森林与二叉树的转换方法。 了解最优树的特性,掌握建立最优树和哈夫曼编码的方法。,

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报