数据结构第六章树和二叉树_第1页
数据结构第六章树和二叉树_第2页
数据结构第六章树和二叉树_第3页
数据结构第六章树和二叉树_第4页
数据结构第六章树和二叉树_第5页
已阅读5页,还剩118页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、6.1 树的类型定义树的类型定义6.2 6.2 二叉树的类型定义二叉树的类型定义6.3 二叉树的存储结构二叉树的存储结构6.4 二叉树的遍历二叉树的遍历6.5 线索二叉树线索二叉树6.6 树和森林的表示方法树和森林的表示方法6.7 树和森林的遍历树和森林的遍历6.8 哈夫曼树与哈夫曼编码哈夫曼树与哈夫曼编码6.1 树的类型定义树的类型定义数据对象数据对象 d:d是具有相同特性的数据元素的集合。是具有相同特性的数据元素的集合。 若若d为空集,则称为空树;为空集,则称为空树; 否则否则: (1) 在在d中存在唯一的称为根的数据元素中存在唯一的称为根的数据元素root, (2) 当当n1时,其余结点

2、可分为时,其余结点可分为m (m0)个互个互 不相交的有限集不相交的有限集t1, t2, , tm, 其中每一其中每一 棵子集本身又是一棵符合本定义的树,棵子集本身又是一棵符合本定义的树, 称为根称为根root的子树。的子树。 数据关系数据关系 r:abcdefghijmkl例如例如: :基基 本本 术术 语语结点结点: :结点的度结点的度: :树的度树的度: :叶子结点叶子结点: :分支结点分支结点: :数据元素+ +若干指向子树的分支分支的个数树中所有结点的度的最大值度为零的结点度大于零的结点dhijm(从根到结点的)路径:路径:孩子孩子结点、双亲双亲结点、兄弟兄弟结点、堂兄弟祖先祖先结点

3、、子孙子孙结点结点的层次结点的层次: :树的深度:树的深度: 由从根根到该结点所经分支和结点构成abcdefghijmkl假设根结点的层次为1,第l 层的结点的子树根结点的层次为l+1树中叶子结点所在的最大层次任何一棵非空树是一个二元组 tree = (root,f)其中:其中:root 被称为根结点, f 被称为子树森林森林:森林:是 m(m0)棵互不相交的树的集合arootbefklcgdhijmf() 有确定的根;() 树根和子树根之间为有向关系。有向树:有向树:有序树:有序树:子树之间存在确定的次序关系。无序树:无序树:子树之间不存在确定的次序关系。对比对比树型结构树型结构和和线性结构

4、线性结构的结构特点的结构特点线性结构线性结构树型结构树型结构第一个数据元素第一个数据元素 ( (无前驱无前驱) ) 根结点根结点 ( (无前驱无前驱) )最后一个数据元素最后一个数据元素 (无后继无后继)多个叶子结点多个叶子结点 ( (无后继无后继) )其它数据元素其它数据元素( (一个前驱、一个前驱、 一个后继一个后继) )其它数据元素其它数据元素( (一个前驱、一个前驱、 多个后继多个后继) )6.2 二叉树的类型定义二叉树的类型定义 二叉树或为空树空树;或是由一个根结根结点点加上两棵两棵分别称为左子树左子树和右子树的、互不交的互不交的二叉树二叉树组成。abcdefghk根结点左子树右子树

5、ef二叉树的五种基本形态:二叉树的五种基本形态:n空树空树只含根结点只含根结点nnnlrr右子树为空树右子树为空树l左子树为空树左子树为空树左右子左右子树均不树均不为空树为空树二叉树二叉树的重要特性的重要特性 性质性质 1 : 在二叉树的第 i 层上至多有2i-1 个结点。 (i1)用归纳法用归纳法证明证明: 归纳基归纳基: 归纳假设:归纳假设: 归纳证明:归纳证明:i = 1 层时,只有一个根结点, 2i-1 = 20 = 1;假设对所有的 j,1 j i,命题成立;二叉树上每个结点至多有两棵子树,则第 i 层的结点数 = 2i-2 2 = 2i-1 。 性质性质 2 : 深度为 k 的二叉

6、树上至多含 2k-1 个结点(k1)证明:证明: 基于上一条性质,深度为 k 的二叉树上的结点数至多为 20+21+ +2k-1 = 2k-1 性质性质 3 : 对任何一棵二叉树,若它含有n0 个叶子结点、n2 个度为 2 的结点,则必存在关系式:n0 = n2+1证明:证明:设设 二叉树上结点总数 n = n0 + n1 + n2又又 二叉树上分支总数 b = n1 + 2n2而 b = n-1 = n0 + n1 + n2 - 1由此,由此, n0 = n2 + 1两类两类特殊特殊的二叉树:的二叉树:满二叉树满二叉树:指的是深度为k且含有2k-1个结点的二叉树。完全二叉树完全二叉树:树中所

7、含的 n 个结点和满二叉树中编号编号为为 1 至至 n 的结点的结点一一对应。123456789 10 11 12 13 14 15abcdefghij 性质性质 4 : 具有 n 个结点的完全二叉树的深度深度为 log2n +1证明:证明:设设 完全二叉树的深度为 k 则根据第二条性质得 2k-1 n 2k 即 k-1 log2 n n,则该结点无左孩子, 否则,编号为 2i 的结点为其左孩子左孩子结点;(3) 若 2i+1n,则该结点无右孩子结点, 否则,编号为2i+1 的结点为其右孩子右孩子结点。6.3 二叉树的存储结构二叉树的存储结构二、二叉树的链式二、二叉树的链式 存储表示存储表示一

8、、一、 二叉树的顺序二叉树的顺序 存储表示存储表示#define max_tree_size 100 / 二叉树的最大结点数typedef telemtype sqbitreemax_tree_size; / 0号单元存储根结点sqbitree bt;一、一、 二叉树的顺序存储表示二叉树的顺序存储表示例如例如: a b d c e f 0 1 2 3 4 5 6 7 8 9 10 11 12 13abcdef1401326二、二叉树的链式存储表示二、二叉树的链式存储表示1. 1. 二叉链表二叉链表2三叉链表三叉链表3 3双亲链表双亲链表4线索链表线索链表adebcf rootlchild da

9、ta rchild结点结构结点结构:1. 1. 二叉链表二叉链表typedef struct bitnode / 结点结构结点结构 telemtype data; struct bitnode *lchild, *rchild; / 左右孩子指针 bitnode, *bitree;lchild data rchild结点结构结点结构:c 语言的类型描述如下语言的类型描述如下: :rootadebcf 2三叉链表三叉链表parent lchild data rchild结点结构结点结构: typedef struct tritnode / 结点结构结点结构 telemtype data; str

10、uct tritnode *lchild, *rchild; / 左右孩子指针 struct tritnode *parent; /双亲指针 tritnode, *tritree;parent lchild data rchild结点结构结点结构:c 语言的类型描述如下语言的类型描述如下: :结点结构结点结构:3 3双亲链表双亲链表 data parentabdcef0b41d42c03e14a-15f36lrtaglrrrrl根根 typedef struct bptnode / 结点结构结点结构 telemtype data; int *parent; / 指向双亲的指针 char lrt

11、ag; / 左、右孩子标志域 bptnode typedef struct bptree / 树结构树结构 bptnode nodesmax_tree_size; int num_node; / 结点数目 int root; / 根结点的位置 bptree 二叉树的主要基本操作二叉树的主要基本操作:(1) init (bt) 构造一棵空二叉树、(2) create(x,lbt,rbt) 生成一棵以x为根结点,以二叉树lbt和rbt为左子树和右子树的二叉树(3) insertl(x,parent)将值为x的结点插入到二叉树中结点parent的左孩子位置。如果结点parent原来有左孩子结点,则将

12、结点parent原来的左孩子结点作为结点x的左孩子结点。(4) insertr(x,parent)将值为x的结点插入到二叉树中结点parent的右孩子位置。如果结点parent原来有右孩子结点,则将结点parent原来的右孩子结点作为结点x的右孩子结点。(5)deletel(bt,parent)在二叉树bt中删除结点parent的左子树(6) deleter(bt,parent)在二叉树bt中删除结点parent的右子树(7)search(bt,x)在二叉树bt中查找数据元素x(8)traverse(bt)按某种方式遍历二叉树 实现算法(1)init(bt)int init( bitree b

13、t) if(bt =(bitree)malloc(sizeof(bitnode) =null) return 0;bt-lchild=null;bt-rchild=null;return 1; (2)create(x,lbt,rbt)bitree create(x,lbt,rbt) bitree p; if(bt =(bitree)malloc(sizeof(bitnode) =null) return null;p-data = x;p-lchild=lbt;p-rchild=rbt;return p; (3)insertl(x, parent)bitree insertl(x, paren

14、t) bitree p; if(parent=null) return null; if(bt =(bitree)malloc(sizeof(bitnode) =null) return null;p-data = x; p-lchild=null; p-rchild=null;if( parent-lchild=null) parent-lchild=p;else p-lchild=parent-lchild; parent-lchild=p; (5)deletel(bt, parent)bitree deletel(bt, parent) bitree p; if(parent=null|

15、 parent-lchild=null) return null;p= parent-lchild;parent-lchild=null;free(p); return bt; 6.4二叉树的遍历二叉树的遍历一、问题的提出一、问题的提出二、先左后右的遍历算法二、先左后右的遍历算法三、算法的递归描述三、算法的递归描述四、中序遍历算法的非递归描述四、中序遍历算法的非递归描述四四、遍历算法的应用举例遍历算法的应用举例 顺着某一条搜索路径巡访巡访二叉树中的结点,使得每个结点均被访问一均被访问一次次,而且仅被访问一次仅被访问一次。一、问题的提出一、问题的提出“访问访问”的含义可以很广,如:输出结点的信息

16、等。 “遍历遍历”是任何类型均有的操作,对线性结构而言,只有一条搜索路径(因为每个结点均只有一个后继),故不需要另加讨论。而二叉树是非线性结构, 每个结点有两个后继每个结点有两个后继,则存在如何遍历存在如何遍历即按什么样的搜索搜索路径路径进行进行遍历的问题。 对对“二叉树二叉树”而言,可以有而言,可以有三条搜索路径:三条搜索路径: 1先上后下先上后下的按层次遍历; 2先左先左(子树)后右后右(子树)的遍历; 3先右先右(子树)后左后左(子树)的遍历。二、先左后右的遍历算法二、先左后右的遍历算法先先(根)序的遍历算法中中(根)序的遍历算法后后(根)序的遍历算法根根左子树右子树根根根根根根根根根根

17、 若二叉树为空树,则空操作;否则,(1)访问根结点;(2)先序遍历左子树;(3)先序遍历右子树。先(根)序的遍历算法:先(根)序的遍历算法: 若二叉树为空树,则空操作;否则,(1)中序遍历左子树;(2)访问根结点;(3)中序遍历右子树。中(根)序的遍历算法:中(根)序的遍历算法: 若二叉树为空树,则空操作;否则,(1)后序遍历左子树;(2)后序遍历右子树;(3)访问根结点。后(根)序的遍历算法:后(根)序的遍历算法:abcdefghk例如:例如:先序序列:先序序列:中序序列:中序序列:后序序列:后序序列:a b c d e f g h kb d c a e h g k fd c b h k g

18、 f e a三、算法的递归描述三、算法的递归描述void preorder (bitree t) / 先序遍历二叉树 if (t) printf(“%d”,t-data); / 访问结点 preorder(t-lchild, visit); / 遍历左子树 preorder(t-rchild, visit);/ 遍历右子树 前序遍历算法的非递归描述前序遍历算法的非递归描述void preorder(bitree bt)bitree *stackmaxsize ,p; int top; if(bt!=null) top=1; stacktop=b; /根结点入栈 while(top0) /栈不为

19、空时循环 p=stacktop-; /退栈并访问该结点 printf(“%d”,p-data); if(p-rchild!=null) /右孩子入栈 stacktop=p-rchild; top+; if(p-lchild!=null) /左孩子入栈 stacktop=p-lchild; top+; / while /if中序遍历算法的非递归描述中序遍历算法的非递归描述bitnode *gofarleft(bitree t, stack *s) if (!t ) return null; while (t-lchild ) push(s, t); t = t-lchild; return t;

20、void inorder(bitree t, void (*visit) (telemtype& e) stack *s; t = gofarleft(t, s); / 找到最左下的结点 while(t) visit(t-data); if (t-rchild) else if ( !stackempty(s ) t = pop(s); / 退栈 else t = null; / 栈空表明遍历结束 / while t = gofarleft(t-rchild, s);四四、遍历算法的应用举例遍历算法的应用举例2、统计二叉树中叶子结点的个数、统计二叉树中叶子结点的个数3、求二叉树的深度、

21、求二叉树的深度(后序遍历后序遍历)4 4、建立二叉树的存储结构、建立二叉树的存储结构1、查询二叉树中某个结点、查询二叉树中某个结点1. 在二叉树不空的前提下,和根结点的元素进行比较,若相等,则找到返回 true;2. 否则在左子树中进行查找,若找到,则返回 true;3. 否则继续在右子树中进行查找,若找到,则返回 true,否则返回 false;status preorder (bitree t, elemtype x) / 若二叉树中存在和若二叉树中存在和 x 相同的元素,则相同的元素,则 p p 指向该结点并返回指向该结点并返回 ok,/ 否则返回否则返回 false if (t) if

22、 (t-data=x) p = t; return ok, /if else return false;else if (preorder(t-lchild, x) return ok; else return(preorder(t-rchild, x) ;/else2、统计二叉树中叶子结点的个数、统计二叉树中叶子结点的个数int count=0;int countleaf (bitree t,count) if( t ) if (!t-lchild)& (!t-rchild) count+; / 对叶子结点计数 countleaf( t-lchild, count); countle

23、af( t-rchild, count); return count; else return 0; / countleaf3、求二叉树的深度、求二叉树的深度(后序遍历后序遍历)算法基本思想算法基本思想: : 从二叉树深度的定义可知,二叉树的二叉树的深度应为其左、右子树深度的最大值加深度应为其左、右子树深度的最大值加1 1。由此,需先分别求得左、右子树的深度,需先分别求得左、右子树的深度,算法中“访问结点”的操作为:求得左、求得左、右子树深度的最大值,然后加右子树深度的最大值,然后加 1 1 。 首先分析二叉树的深度二叉树的深度和它的左左、右子右子树深度树深度之间的关系。int depth (

24、bitree t ) / 返回二叉树的深度 if ( !t ) depthval = 0; else depthleft = depth( t-lchild ); depthright= depth( t-rchild ); depthval = 1 + (depthleft depthright ? depthleft : depthright); return depthval;5 5、建立二叉树的存储、建立二叉树的存储结构结构不同的定义方法相应有不同的不同的定义方法相应有不同的存储结构的建立算法存储结构的建立算法 以字符串的形式以字符串的形式 “根根 左子树左子树 右子树右子树”定义一棵

25、二叉树定义一棵二叉树例如例如: :以空白字符“ ”表示abcdab c d 空树空树只含一个根结点只含一个根结点的二叉树的二叉树a以字符串“a ”表示以下列字符串表示int createbitree(bitree &t) scanf(&ch); if (ch= ) t = null; else if (!(t = new bitnode) exit(overflow); t-data = ch; / 生成根结点 createbitree(t-lchild); / 构造左子树 createbitree(t-rchild); / 构造右子树 return 1; / createbi

26、treea b c d a bcd上页算法执行过程举例如下:atbcdscanf(&ch);if (ch= ) t = null;else if (!(t = new bitnode) exit(overflow); t-data = ch;createbitree(t-lchild); createbitree(t-rchild); 仅知二叉树的先序序列“abcdefg” 能否唯一确定一棵二叉树?由二叉树的先序和中序序列建树由二叉树的先序和中序序列建树 如果同时已知二叉树的中序序列“cbdaegf”,则会如何? 二叉树的先序序列二叉树的中序序列左子树左子树左子树左子树 右子树右子树右

27、子树右子树根根根根a b c d e f gc b d a e g f例如例如: :aab bccddeeffggabcdefg先序序列中序序列6.5线索二叉树线索二叉树 何谓线索二叉树?何谓线索二叉树? 线索链表的遍历算法线索链表的遍历算法一、一、何谓线索二叉树?何谓线索二叉树?遍历二叉树的结果是, 求得结点的一个线性序列。abcdefghk例如:先序先序序列: a b c d e f g h k中序中序序列: b d c a h g k f e后序后序序列: d c b h k g f e a指向该线性序列中的“前驱”和 “后继” 的指针指针,称作“线线索索”与其相应的二叉树,称作 “线索

28、二叉树线索二叉树”包含 “线索” 的存储结构,称作 “线索链线索链表表”a b c d e f g h k d c b e 对对线索链表线索链表中结点的约定:中结点的约定: 在二叉链表的结点中增加两个标志域增加两个标志域,并作如下规定:若该结点的左子树不空,若该结点的左子树不空,则lchild域的指针指向其左子树, 且左标志域的值为“0”; 否则,lchild域的指针指向其“前驱”, 且左标志的值为“1” 。若该结点的右子树不空,若该结点的右子树不空,则rchild域的指针指向其右子树, 且右标志域的值为 “0”;否则,rchild域的指针指向其“后继”, 且右标志的值为“1”。 如此定义的二

29、叉树的存储结构称作如此定义的二叉树的存储结构称作“线索链表线索链表”typedef struct bithrnod telemtype data; struct bithrnode *lchild, *rchild; / 左右指针 pointerthr ltag, rtag; / 左右标志 bithrnode, *bithrtree;线索链表的类型描述: typedef enum link, thread pointerthr; / link=0:指针,thread=1:线索二、线索链表的遍历算法二、线索链表的遍历算法: for ( p = firstnode(t); p; p = succ(

30、p) ) visit (p);由于在线索链表中添加了遍历中得到的“前驱”和“后继”的信息,从而简化了遍历的算法。例如例如: 对中序线索化链表的遍历算法对中序线索化链表的遍历算法 中序遍历的第一个结点中序遍历的第一个结点 ? 在中序线索化链表中结点的后继在中序线索化链表中结点的后继 ?左子树上处于“最左下最左下”(没有左子树)的结点若若无右子树,则为则为后继线索后继线索所指结点否则为否则为对其右子树右子树进行中序遍历遍历时访问的第一个结点第一个结点void inordertraverse_thr(bithrtree t) p = t-lchild; / p指向根结点 while (p != t)

31、 / 空树或遍历结束时,p=t while (p-ltag=link) p = p-lchild; visit(p-data) / 第一个结点 while (p-rtag=thread & p-rchild!=t) p = p-rchild; visit(p-data) / 访问后继结点 p = p-rchild; / p进至其右子树根 / inordertraverse_thr 6.6 树和森林树和森林 的表示方法的表示方法树的三种存储结构树的三种存储结构一、一、双亲表示法双亲表示法二、二、孩子链表表示法孩子链表表示法三、三、树的二叉链表树的二叉链表( (孩子孩子- -兄弟)兄弟)

32、存储表示法存储表示法abcdefgr=0n=70 a -11 b 02 c 03 d 04 e 2 5 f 26 g 5data parent一、双亲表示法一、双亲表示法: typedef struct ptnode elem data; int parent; / 双亲位置域 ptnode; data parent#define max_tree_size 100结点结构结点结构:c语言的类型描述语言的类型描述: :typedef struct ptnode nodes max_tree_size; int r, n; / 根结点的位置和结点个数 ptree;树结构树结构:r=0n=7 da

33、ta firstchildabcdefg0 a -11 b 02 c 03 d 04 e 25 f 26 g 464 5 1 2 3二、孩子链表表示法二、孩子链表表示法:-1 0 0 0 2 2 4typedef struct ctnode int child; struct ctnode *nextchild; *childptr;孩子结点结构孩子结点结构: child nextchildc语言的类型描述语言的类型描述: : typedef struct elem data; childptr firstchild; / 孩子链的头指针 ctbox;双亲结点结构双亲结点结构 data fir

34、stchildtypedef struct ctbox nodesmax_tree_size; int n, r; / 结点数和根结点的位置 ctree;树结构树结构:abcdefgroot ab c e d f g ab c e d f g 三、树的二叉链表三、树的二叉链表 (孩子孩子-兄弟)存储表示法兄弟)存储表示法roottypedef struct csnode elem data; struct csnode *firstchild, *nextsibling; csnode, *cstree;c语言的类型描述语言的类型描述: :结点结构结点结构: firstchild data n

35、extsibling 森林和二叉树的对应关系森林和二叉树的对应关系设设森林森林 f = ( t1, t2, , tn ); t1 = ( root,t11, t12, , t1m );二叉树二叉树 b =( lbt, node(root), rbt );由森林转换成二叉树由森林转换成二叉树的转换规则为:若 f = ,则 b = ; 由 root( t1 ) 对应得到node(root);否则,由 (t11, t12, , t1m ) 对应得到 lbt;由 (t2, t3, tn ) 对应得到 rbt。由二叉树转换为森林由二叉树转换为森林的转换规则为:由lbt 对应得到 ( t11, t12,

36、,t1m);若 b = , 则 f = ;否则,由 node(root) 对应得到 root( t1 );由rbt 对应得到 (t2, t3, , tn)。t1t11,t12,t1mt2,tnlbtrbtroot 由此,树和森林的各种操作均可与二叉树的各种操作相对应。 应当注意的是,应当注意的是,和树对应的二叉树,其左、右子树的概念已改变为: 左是孩子,右是兄弟左是孩子,右是兄弟6.7树和森林的遍历树和森林的遍历一、树的遍历一、树的遍历二、森林的遍历二、森林的遍历三、树的遍历的应用三、树的遍历的应用树的遍历可有树的遍历可有3条搜索路径条搜索路径:按层次遍历按层次遍历:先根先根(次序次序)遍历遍

37、历:后根后根(次序次序)遍历遍历: 若树不空,则先访问根结点,然后若树不空,则先访问根结点,然后依次先根遍历各棵子树。依次先根遍历各棵子树。 若树不空,则先依次后根遍历各棵若树不空,则先依次后根遍历各棵子树,然后访问根结点。子树,然后访问根结点。 若树不空,则自上而下自左至右若树不空,则自上而下自左至右访问树中每个结点。访问树中每个结点。 层次遍历时顶点层次遍历时顶点的访问次序:的访问次序: a b c de f g h i j k 先根遍历时顶点先根遍历时顶点的访问次序:的访问次序:a b e f c d g h i j k 后根遍历时顶点后根遍历时顶点的访问次序:的访问次序:e f b c

38、 i j k h g d aa b c d e f g h i j k b c de f g h i j k1。森林中第一棵树的根结点;2。森林中第一棵树的子树森林;3。森林中其它树构成的森林。可以分解成三部分:森林森林 若森林不空,则访问访问森林中第一棵树的根结点;先序遍历先序遍历森林中第一棵树的子树森林;先序遍历先序遍历森林中(除第一棵树之外)其 余树构成的森林。先序遍历先序遍历森林的遍历森林的遍历即:依次从左至右依次从左至右对森林中的每一棵树树进行先根遍历先根遍历。 中序遍历中序遍历 若森林不空,则中序遍历中序遍历森林中第一棵树的子树森林;访问访问森林中第一棵树的根结点;中序遍历中序遍历森林中(除第一棵树之外)其 余树构成的森林。即:依次从左至右依次从左至右对森林中的每一棵树树进行后根遍历后根遍历。 树的遍历和二叉树遍历树的遍历和二

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论