版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、6.1 树的类型定义树的类型定义6.2 二叉树的类型定义二叉树的类型定义6.3 二叉树的存储构造二叉树的存储构造6.4 二叉树的遍历二叉树的遍历6.5 线索二叉树线索二叉树6.6 树和森林的表示方法树和森林的表示方法6.7 树和森林的遍历树和森林的遍历6.8 哈夫曼树与哈夫曼编码哈夫曼树与哈夫曼编码目目 录录6.1 树的类型定义树的类型定义D是具有一样特性的数据元素的集合。是具有一样特性的数据元素的集合。假设假设D为空集,为空集,那么称为空树;那么称为空树;否那么否那么:(1) 在在D中存在独一的称为根的数据元素中存在独一的称为根的数据元素root,(2) 当当n1时,其他结点可分为时,其他结
2、点可分为m (m0)个互个互 不相交的有限集不相交的有限集T1, T2, , Tm, 其中每一其中每一 个子集本身又是一棵符合本定义的树,个子集本身又是一棵符合本定义的树, 称为根称为根root的子树。的子树。ADT树的例如树的例如Root(T) / 求树的根结求树的根结点点 Value(T, cur_e) / 求当前结点的元素求当前结点的元素值值 Parent(T, cur_e) / 求当前结点的双亲结求当前结点的双亲结点点LeftChild(T, cur_e) / 求当前结点的最左孩求当前结点的最左孩子子 RightSibling(T, cur_e) / 求当前结点的右兄求当前结点的右兄弟
3、弟TreeEmpty(T) / 断定树能否为空树断定树能否为空树 TreeDepth(T) / 求树的深度求树的深度TraverseTree( T, Visit() ) / 遍历遍历InitTree(&T) / 初始化置空树初始化置空树 CreateTree(&T, definition) / 按定义构造树按定义构造树Assign(T, cur_e, value) / 给当前结点赋值给当前结点赋值InsertChild(&T, &p, i, c) / 将以将以c为根的树插入为结点为根的树插入为结点p的第的第i棵棵子树子树 ClearTree(&T) /
4、将树清空 DestroyTree(&T) / 销毁树的构造销毁树的构造DeleteChild(&T, &p, i) / 删除结点删除结点p的第的第i棵子棵子树树ABCDEFGHIJMKLA( B(E, F(K, L), C(G), D(H, I, J(M) )T1T3T2树根() 有确定的根;有确定的根;() 树根和子树根之间为有向关系。树根和子树根之间为有向关系。子树之间存在确定的次序关系。子树之间存在确定的次序关系。子树之间不存在确定的次序关系。子树之间不存在确定的次序关系。对比树型构造和线性构造对比树型构造和线性构造的构造特点的构造特点线性构造线性构造树型构造树型
5、构造第一个数据元素第一个数据元素 ( (无前驱无前驱) ) 根结点 (无前驱)最后一个数据元素最后一个数据元素 (无后继无后继)多个叶子结点多个叶子结点 ( (无后继无后继) )其它数据元素其它数据元素( (一个前驱、一个前驱、 一个后继一个后继) )其它数据元素其它数据元素( (一个前驱、一个前驱、 多个后继多个后继) )基基 本本 术术 语语结点结点: :结点的度结点的度: :树的度树的度: :叶子结点叶子结点: :分支结点分支结点: :数据元素数据元素+ +假设干指向子树的分支假设干指向子树的分支分支的个数分支的个数树中一切结点的度的最大值树中一切结点的度的最大值度为零的结点度为零的结点
6、度大于零的结点度大于零的结点DHIJM( (从根到结点的从根到结点的) )途径:途径:孩子结点、双亲结点、孩子结点、双亲结点、兄弟结点、堂兄弟兄弟结点、堂兄弟祖先结点、子孙结点祖先结点、子孙结点结点的层次结点的层次: :树的深度:树的深度: 由从根到该结点由从根到该结点所经分支和结点构成所经分支和结点构成ABCDEFGHIJMKL假设根结点的层次为假设根结点的层次为1,1,第第l l 层层的结点的子树根结点的层次为的结点的子树根结点的层次为l+1l+1树中叶子结点所在的最大层次树中叶子结点所在的最大层次任何一棵非空树是一个二元组任何一棵非空树是一个二元组 Tree = root,F其中:其中:
7、root 被称为根结点,被称为根结点, F 被称为子树森林被称为子树森林森林:森林:是是mm0棵互棵互不相交的树的集合不相交的树的集合ArootBCDEFGHIJMKLF6.2 二叉树的类型定义二叉树的类型定义 二叉树或为空树;或是由一二叉树或为空树;或是由一个根结点加上两棵分别称为左个根结点加上两棵分别称为左子树和右子树的、互不交的二子树和右子树的、互不交的二叉树组成。叉树组成。ABCDEFGHK根结点根结点左子树左子树右子树右子树NNNNLRRL空树空树只含根结点只含根结点右子树为空树右子树为空树左子树为空树左子树为空树左右子左右子树均不树均不为空树为空树二叉树的五种根本形状:二叉树的五种
8、根本形状:查查 找找 类类插插 入入 类类删删 除除 类类 二叉树的主要根本操作二叉树的主要根本操作 Root(T); Value(T, e); Parent(T, e); LeftChild(T, e); RightChild(T, e); LeftSibling(T, e); RightSibling(T, e); BiTreeEmpty(T); BiTreeDepth(T); PreOrderTraverse(T, Visit(); InOrderTraverse(T, Visit(); PostOrderTraverse(T, Visit(); LevelOrderTraverse(T
9、, Visit(); InitBiTree(&T); Assign(T, &e, value); CreateBiTree(&T, definition); InsertChild(T, p, LR, c);ClearBiTree(&T); DestroyBiTree(&T);DeleteChild(T, p, LR);二叉树二叉树的重要特性的重要特性性质性质1 : 在二叉树的第在二叉树的第 i 层上至多有层上至多有2i-1 个个结点。结点。 (i1)i = 1 层时,只需一个根结点,层时,只需一个根结点,2i-1 = 20 = 1;假设对一切的假设对一
10、切的 j,1 j i,命题成立,命题成立;二叉树上每个结点至多有两棵子树,二叉树上每个结点至多有两棵子树,那么第那么第 i 层的结点数层的结点数 = 2i-2 2 = 2i-1 。性质性质 2 : 深度为深度为 k 的二叉树上至多含的二叉树上至多含 2k-1 个结点个结点k1证明:证明: 基于上一条性质,深度为基于上一条性质,深度为 k 的二叉的二叉树上的结点数至多为树上的结点数至多为 20+21+ +2k-1 = 2k-1 性质性质 3 : 对任何一棵二叉树,假设它含对任何一棵二叉树,假设它含有有n0 个叶子结点、个叶子结点、n2 个度为个度为 2 的结点,那么必存在关系式:的结点,那么必存
11、在关系式:n0 = n2+1证明:证明:设设 二叉树上结点总数二叉树上结点总数 n = n0 + n1 + n2又又 二叉树上分支总数二叉树上分支总数 b = n1+2n2 而而 b = n-1 = n0 + n1 + n2 - 1由此,由此, n0 = n2 + 1满二叉树:深度满二叉树:深度为为k且含有且含有2k-1个结点的二叉树。个结点的二叉树。完全二叉树:树完全二叉树:树中所含的中所含的 n 个结个结点和满二叉树中点和满二叉树中编号为编号为 1 至至 n 的的结点一一对应。结点一一对应。123456789 10 11 12 13 14 15abcdefghij两类特殊的二叉树:两类特殊
12、的二叉树:证明:证明:设设 完全二叉树的深度为完全二叉树的深度为 k 那么根据第二条性质得那么根据第二条性质得 2k-1 n 2k 即即 k-1 log2 n n,那么该结点无左孩子,那么该结点无左孩子, 否那么,编号为否那么,编号为 2i 的结点为其左孩子结点;的结点为其左孩子结点;(3) 假设假设 2i+1n,那么该结点无右孩子结点,那么该结点无右孩子结点, 否那么,编号为否那么,编号为2i+1 的结点为其右孩子结点。的结点为其右孩子结点。性质性质 5 :二二. . 二叉树的链式二叉树的链式 存储表示存储表示一一. 二叉树的顺序二叉树的顺序 存储表示存储表示6.3 二叉树的存储构造二叉树的
13、存储构造#define MAX_TREE_SIZE 100 / 二叉树的最大结点数二叉树的最大结点数typedef TElemType SqBiTreeMAX_TREE_SIZE; / 1号单元存储根结点号单元存储根结点SqBiTree bt; 一一. 二叉树的顺序存储表示二叉树的顺序存储表示 A B D C E FABCDEF 0 1 2 3 4 5 6 7 8 9 10 11 12 13 142511437例如例如:1. 二叉链表二叉链表2三叉链表三叉链表3双亲链表双亲链表4线索链表线索链表二二. . 二叉树的链式存储表示二叉树的链式存储表示ADEBCF rootlchild data r
14、child结点构造结点构造:1. 1. 二叉链表二叉链表typedef struct BiTNode / 结点构造结点构造 TElemType data; struct BiTNode *lchild, *rchild; / 左、右孩子指针左、右孩子指针 BiTNode, *BiTree;lchild data rchild结点构造结点构造:C 言语的类型描画如下言语的类型描画如下:ADEBCF root parent lchild data rchild结点构造结点构造:2三叉链表三叉链表 typedef struct TriTNode / 结点构造结点构造 TElemType data;
15、struct TriTNode *lchild, *rchild; / 左、右孩子指针左、右孩子指针 struct TriTNode *parent; /双亲指针双亲指针 TriTNode, *TriTree;parent lchild data rchild结点构造结点构造:C 言语的类型描画如下言语的类型描画如下:LRRRL0123456B2C0A -1D2E3F4 data parent结点构造结点构造:LRTag3 3双亲链表双亲链表 typedef struct BPTNode / 结点构造结点构造 TElemType data; int parent; / 指向双亲的指针指向双亲的
16、指针 char LRTag; / 左、右孩子标志域左、右孩子标志域 BPTNode typedef struct BPTree / 树构造树构造 BPTNode nodesMAX_TREE_SIZE; int num_node; / 结点数目结点数目 int root; / 根结点的位置根结点的位置 BPTree6.4二叉树的遍历二叉树的遍历一、问题的提出一、问题的提出二、先左后右的遍历算法二、先左后右的遍历算法三、算法的递归描画三、算法的递归描画四、中序遍历算法的非递归描画四、中序遍历算法的非递归描画五、遍历算法的运用举例五、遍历算法的运用举例 顺着某一条搜索途径巡访二叉树顺着某一条搜索途径
17、巡访二叉树中的结点,使得每个结点均被访问一中的结点,使得每个结点均被访问一次,而且仅被访问一次。次,而且仅被访问一次。一. 问题的提出“访问的含义可以很广,如:输出结访问的含义可以很广,如:输出结点的信息等。点的信息等。 “遍历是任何类型均有的操作,遍历是任何类型均有的操作,对线性构造而言,只需一条搜索路对线性构造而言,只需一条搜索路径径(由于每个结点均只需一个后继由于每个结点均只需一个后继),故不需求另加讨论。而二叉树是非故不需求另加讨论。而二叉树是非线性构造,每个结点有两个后继,线性构造,每个结点有两个后继,那么存在如何遍历即按什么样的搜索那么存在如何遍历即按什么样的搜索途径遍历的问题。途
18、径遍历的问题。 对对“二叉树而言,可以有二叉树而言,可以有三条搜索途径:三条搜索途径:1先上后下的按层次遍历;先上后下的按层次遍历;2先左先左(子树子树)后右后右(子树子树)的遍历;的遍历;3先右先右(子树子树)后左后左(子树子树)的遍历。的遍历。先根序的遍历算法先根序的遍历算法中根序的遍历算法中根序的遍历算法后根序的遍历算法后根序的遍历算法二. 先左后右的遍历算法 假设二叉树为空树,那么空操作;否那么,假设二叉树为空树,那么空操作;否那么,1访问根结点;访问根结点;2先序遍历左子树;先序遍历左子树;3先序遍历右子树。先序遍历右子树。先根序的遍历算法:先根序的遍历算法: 假设二叉树为空树,那么
19、空操作;否那么,假设二叉树为空树,那么空操作;否那么,1中序遍历左子树;中序遍历左子树;2访问根结点;访问根结点;3中序遍历右子树。中序遍历右子树。中根序的遍历算法:中根序的遍历算法: 假设二叉树为空树,那么空操作;否那么,假设二叉树为空树,那么空操作;否那么,1后序遍历左子树;后序遍历左子树;2后序遍历右子树;后序遍历右子树;3访问根结点。访问根结点。后根序的遍历算法:后根序的遍历算法:void Preorder (BiTree T, void( *visit)(TElemType& e) / 先序遍历二叉树先序遍历二叉树 if (T) visit(T-data); / 访问结点访问
20、结点 Preorder(T-lchild, visit); / 遍历左子树遍历左子树 Preorder(T-rchild, visit);/ 遍历右子树遍历右子树 三. 算法的递归描画BiTNode *GoFarLeft(BiTree T, Stack &S) if (!T ) return NULL; while (T-lchild ) / 直到最左端直到最左端 Push(S, T); T = T-lchild; return T;四. 中序遍历算法的非递归描画abcdefghijvoid Inorder_I( BiTree T, void (*visit)(TelemType&am
21、p; e) ) Stack S; InitStack(S); t = GoFarLeft(T, S); / 找到最左下的结点找到最左下的结点 while (t) visit(t-data); if (t-rchild) t = GoFarLeft(t-rchild, S); else if (!StackEmpty(S ) / 栈不空时退栈栈不空时退栈 t = Pop(S); else t = NULL; / 栈空阐明遍历终了栈空阐明遍历终了 1. 统计二叉树中叶子结点的个数统计二叉树中叶子结点的个数 (先序遍历,先序遍历, 习题习题6.422. 求二叉树的深度求二叉树的深度 (后序遍历,参见
22、习题后序遍历,参见习题6.443. 复制二叉树复制二叉树 (后序遍历,参见习题后序遍历,参见习题6.464.4.建立二叉树的存储构造建立二叉树的存储构造五. 遍历算法的运用举例算法根本思想算法根本思想: : 先序先序( (或中序或后序或中序或后序) )遍历二叉树,在遍历二叉树,在遍历过程中查找叶子结点,并计数。遍历过程中查找叶子结点,并计数。 因此,需在遍历算法中增添一个因此,需在遍历算法中增添一个“计计数的参数,并将算法中数的参数,并将算法中“访问结点的访问结点的操作改为操作改为: :假设是叶子,那么计数器增假设是叶子,那么计数器增1 1。1. 统计二叉树中叶子结点的个数统计二叉树中叶子结点
23、的个数习题习题6.42void CountLeaf (BiTree T, int& count) if ( T ) /初值为初值为0 if (!T-lchild & !T-rchild) count+; / 对叶子结点计数对叶子结点计数 CountLeaf( T-lchild, count); CountLeaf( T-rchild, count); 算法根本思想算法根本思想: : 从二叉树深度的定义可知,二叉树的从二叉树深度的定义可知,二叉树的深度应为其左、右子树深度的最大值加深度应为其左、右子树深度的最大值加1 1。由此,需先分别求得左、右子树的深度,由此,需先分别求得左、
24、右子树的深度,算法中算法中“访问结点的操作为访问结点的操作为: :求得左、求得左、右子树深度的最大值,然后加右子树深度的最大值,然后加 1 1 。 首先分析二叉树的深度和它的左、首先分析二叉树的深度和它的左、右子树深度之间的关系。右子树深度之间的关系。2. 求二叉树的深度求二叉树的深度(后序遍历后序遍历) 参见习题参见习题6.44int Depth (BiTree T ) / 前往二叉树的深度前往二叉树的深度 if ( !T ) depthval = 0; else depthLeft = Depth( T-lchild ); depthRight= Depth( T-rchild ); de
25、pthval = 1 + (depthLeft depthRight ? depthLeft : depthRight); return depthval;其根本操作为其根本操作为: :生成一个结点。生成一个结点。根元素根元素T左子树左子树右子树右子树根元素根元素NEWT左子树左子树右子树右子树左子树左子树右子树右子树(后序遍历后序遍历)3. 复制二叉树参见习题复制二叉树参见习题6.46BiTNode *GetTreeNode(TElemType item, BiTNode *lptr , BiTNode *rptr ) if (!(T = (BiTNode*)malloc(sizeof(Bi
26、TNode) exit(1); T- data = item; T- lchild = lptr; T- rchild = rptr; return T; 生成二叉树的一个结点生成二叉树的一个结点(其数据域为其数据域为item,左指针域为左指针域为lptr,右指针域为右指针域为rptr)BiTNode *CopyTree(BiTNode *T) if (!T ) return NULL; if (T-lchild ) newlptr = CopyTree(T-lchild);/复制左子树复制左子树 else newlptr = NULL; if (T-rchild ) newrptr = Co
27、pyTree(T-rchild);/复制右子树复制右子树 else newrptr = NULL; newT=GetTreeNode(T-data,newlptr,newrptr); return newT;问题:问题:ABCDEFGHK D C B H K G F E A例如例如: :以下二叉树以下二叉树的复制过程如下的复制过程如下: :newT4. 4. 建立二叉树的建立二叉树的 存储构造存储构造 以字符串的方式以字符串的方式 根根 左子树左子树 右子树右子树 定义一棵二叉树定义一棵二叉树例如:ABCD以空白字符以空白字符“ 表示表示A(B( ,C( , ),D( , )空树空树只含一个根
28、结点只含一个根结点的二叉树的二叉树A以字符串以字符串“A A 表示表示以以下字符串表示以以下字符串表示Status CreateBiTree(BiTree &T) scanf(&ch); if (ch= ) T = NULL; else if (!(T=(BiTNode*)malloc(sizeof(BiTNode) exit(OVERFLOW); T-data = ch; / 生成根结点生成根结点 CreateBiTree(T-lchild); / 构造左子树构造左子树 CreateBiTree(T-rchild); / 构造右子树构造右子树 return OK; A B C
29、 D A BCD上页算法执行过程举例如下上页算法执行过程举例如下: :ATBCD 按给定的表达式建相应二叉树按给定的表达式建相应二叉树 由先缀表示式建树由先缀表示式建树例如:知表达式的先缀表示式例如:知表达式的先缀表示式 -+ a b c / d e 由原表达式建树由原表达式建树例如:知表达式例如:知表达式 (a+b)c d/e对应先缀表达式对应先缀表达式 -+ a b c / d e的二叉树的二叉树abcde- -+/特点:特点: 操作数为叶子结点,操作数为叶子结点, 运算符为分支结点运算符为分支结点scanf(&ch);if ( In(ch, 字母集字母集 ) 建叶子结点建叶子结点
30、;else 建根结点建根结点; 递归建左子树递归建左子树; 递归建右子树递归建右子树;由先缀表示式建树的算法的根本操作:由先缀表示式建树的算法的根本操作:a+b(a+b)c d/ea+bc 分析表达式和二叉树的关系分析表达式和二叉树的关系:ab+abc+abc+(a+b)cabcde- -+/根本操作根本操作:scanf(&ch);if (In(ch, 字母集字母集 ) 建叶子结点建叶子结点; 暂存暂存; else if (In(ch, 运算符集运算符集) 和前一个运算符比较优先数和前一个运算符比较优先数; 假设当前的优先数假设当前的优先数“高,那么暂存高,那么暂存; 否那么建子树否那
31、么建子树; void CrtExptree(BiTree &T, char exp ) InitStack(S); Push(S, #); InitStack(PTR); p = exp; ch = *p; while (!(GetTop(S)=# & ch=#) if (!IN(ch, OP) CrtNode( t, ch ); / 建叶子结点并入栈建叶子结点并入栈 else if ( ch!= # ) p+; ch = *p; Pop(PTR, T); switch (ch) case ( : Push(S, ch); break; case ) : Pop(S, c);
32、while (c!= ( ) CrtSubtree( t, c); /建二叉树并入建二叉树并入栈栈 Pop(S, c); break; defult : / switch while(!Gettop(S, c) & ( precede(c,ch) CrtSubtree( t, c); Pop(S, c);if ( ch!= # ) Push( S, ch); break;建叶子结点的算法为:建叶子结点的算法为:void CrtNode(BiTree& T,char ch) T=(BiTNode*)malloc(sizeof(BiTNode); T-data = char; T-
33、lchild = T-rchild = NULL; Push( PTR, T );建子树的算法为:建子树的算法为:void CrtSubtree (Bitree& T, char c) T=(BiTNode*)malloc(sizeof(BiTNode); T-data = c; Pop(PTR, rc); T-rchild = rc; Pop(PTR, lc); T-lchild = lc; Push(PTR, T); 仅知二叉树的先序序列仅知二叉树的先序序列“abcdefg 不不能独一确定一棵二叉树,能独一确定一棵二叉树,由二叉树的先序和中序序列建树由二叉树的先序和中序序列建树 假
34、好像时知二叉树的中序序列假好像时知二叉树的中序序列“cbdaegf, 那么会如何?那么会如何? 二叉树的先序序列二叉树的先序序列二叉树的中序序列二叉树的中序序列左子树左子树左子树左子树右子树右子树右子树右子树根根根根a b c d e f gc b d a e g f例如例如: :aab bccddeeffggabcdefg先序序列先序序列中序序列中序序列void CrtBT(BiTree& T, char pre, char ino, int ps, int is, int n ) / 知知preps.ps+n-1为二叉树的先序序列为二叉树的先序序列, / insis.is+n-1为
35、二叉树的中序序列为二叉树的中序序列, /本算法由此两个序列构造二叉链表本算法由此两个序列构造二叉链表 if (n=0) T=NULL; else k=Search(ino, preps);/在中序序列中查在中序序列中查询询 if (k= -1) T=NULL; else T=(BiTNode*)malloc(sizeof(BiTNode);T-data = preps;if (k=is) T-Lchild = NULL;else CrtBT(T-Lchild, pre, ino, ps+1, is, k-is );if (k=is+n-1) T-Rchild = NULL;else CrtBT
36、(T-Rchild, pre, ino, ps+1+(k-is), k+1, n-(k-is)-1 );6.5 线索二叉树线索二叉树 何谓线索二叉树?何谓线索二叉树? 线索链表的遍历算法线索链表的遍历算法 如何建立线索链表?如何建立线索链表?遍历二叉树的结果是,遍历二叉树的结果是, 求得结点的一个线性序列。求得结点的一个线性序列。ABCDEFGHK例如例如: :先序序列先序序列: : A B C D E F G H K A B C D E F G H K中序序列中序序列: : B D C A H G K F E B D C A H G K F E后序序列后序序列: : D C B H K G
37、F E A D C B H K G F E A一一. 何谓线索二叉树?何谓线索二叉树?指向该线性序列中的指向该线性序列中的“前驱和前驱和 “后继后继 的指针,称作的指针,称作“线索线索与其相应的二叉树,与其相应的二叉树,称作称作 “线索二叉树线索二叉树包含包含 “线索线索 的存储的存储构造,称作构造,称作 “线索链线索链表表A B C D E F G H K D C B E 在二叉链表的结点中添加两个标志在二叉链表的结点中添加两个标志域,并作如下规定:域,并作如下规定:假设该结点的左子树不空,假设该结点的左子树不空,那么那么Lchild域的指针指向其左子树,域的指针指向其左子树, 且左标志域的
38、值为且左标志域的值为“指针指针 Link; 否那么,否那么,Lchild域的指针指向其域的指针指向其“前驱前驱, 且左标志的值为且左标志的值为“线索线索 Thread 。假设该结点的右子树不空,假设该结点的右子树不空,那么那么rchild域的指针指向其右子树,域的指针指向其右子树, 且右标志域的值为且右标志域的值为 “指针指针 Link;否那么,否那么,rchild域的指针指向其域的指针指向其“后继,后继, 且右标志的值为且右标志的值为“线索线索 Thread。 如此定义的二叉树的存储构造称作如此定义的二叉树的存储构造称作“线索链表线索链表typedef struct BiThrNod TEl
39、emType 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(p) ) Visit (p);由于在线索链表中添加了遍历中得到的由于在线索链表中添加了遍历中得到的“前驱和前驱和“后继的信息,从而简化了后继的信息,从而简化了遍历的算法。遍历
40、的算法。二二. . 线索链表的遍历算法线索链表的遍历算法例如例如: 对中序线索化链表的遍历算法对中序线索化链表的遍历算法 中序遍历的第一个结点?中序遍历的第一个结点? 在中序线索化链表中结点的后继?在中序线索化链表中结点的后继?左子树上处于左子树上处于“最左下没有左子树最左下没有左子树的结点的结点假设无右子树,那么为后继线索所指假设无右子树,那么为后继线索所指结点结点否那么为对其右子树进展中序遍历否那么为对其右子树进展中序遍历时访问的第一个结点时访问的第一个结点void InOrderTraverse_Thr(BiThrTree T, void (*Visit)(TElemType e) p
41、= T-lchild; / p指向根结点指向根结点 while (p != T) / 空树或遍历终了时,空树或遍历终了时,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进至其右子树根进至其右子树根 在中序遍历过程中修正结点的在中序遍历过程中修正结点的左、右指针域,以保管当前访问结左、右指针域,以
42、保管当前访问结点的点的“前驱和前驱和“后继信息。遍历过后继信息。遍历过程中,附设指针程中,附设指针pre, 并一直坚持指并一直坚持指针针pre指向当前访问的、指针指向当前访问的、指针p所指所指结点的前驱。结点的前驱。三三. 如何建立线索链表?如何建立线索链表?void InThreading(BiThrTree p) if (p) / 对以对以p为根的非空二叉树进展线为根的非空二叉树进展线索化索化 InThreading(p-lchild); / 左子树线索左子树线索化化 if (!p-lchild) / 建前驱线索建前驱线索 p-LTag = Thread; p-lchild = pre;
43、if (!pre-rchild) / 建后继线索建后继线索 pre-RTag = Thread; pre-rchild = p; pre = p; / 坚持坚持 pre 指向指向 p 的前驱的前驱 InThreading(p-rchild); / 右子树线索化右子树线索化 / ifStatus InOrderThreading(BiThrTree &Thrt, BiThrTree T) / 构建中序线索链构建中序线索链表表 if (!(Thrt = (BiThrTree)malloc( sizeof( BiThrNode) exit (OVERFLOW); Thrt-LTag = Li
44、nk; Thrt-RTag=Thread; Thrt-rchild = Thrt; / 添加头结点添加头结点 return OK; / InOrderThreading if (!T) Thrt-lchild = Thrt; else Thrt-lchild = T; pre = Thrt; InThreading(T); pre-rchild = Thrt; /处置最后一个结处置最后一个结点点 pre-RTag = Thread; Thrt-rchild = pre; 6.6 树和森林的树和森林的 表示方法表示方法一一. 双亲表示法双亲表示法二二. 孩子链表表示法孩子链表表示法三三. 树的二
45、叉链表树的二叉链表(孩子孩子-兄弟兄弟 存储表示法存储表示法树的三种存储构造ABCDEFG0 A -11 B 02 C 03 D 04 E 2 5 F 26 G 5r=0n=7data parent一一. 双亲表示法双亲表示法 typedef struct PTNode Elem data; int parent; / 双亲位置域 PTNode; data parent#define MAX_TREE_SIZE 100结点构造结点构造:C言语的类型描画言语的类型描画:typedef struct PTNode nodesMAX_TREE_SIZE; int r, n; / 根结点的位置和结点个
46、数根结点的位置和结点个数 PTree;树构造:ABCDEFG0 A -11 B 02 C 03 D 04 E 25 F 26 G 5r=0n=7 data firstchild 1 2 34 56-1 0 0 0 2 2 4二二. 孩子链表表示法孩子链表表示法typedef struct CTNode int child; struct CTNode *next; *ChildPtr;孩子结点构造孩子结点构造: child nextC言语的类型描画言语的类型描画: typedef struct Elem data; ChildPtr firstchild; / 孩子链的头指针 CTBox;双亲
47、结点构造双亲结点构造 data firstchildtypedef struct CTBox nodesMAX_TREE_SIZE; int n, r; / 结点数和根结点的位置结点数和根结点的位置 CTree;树构造:ABCDEFG AB C E D F Groot AB C E D F G 三三. 树的二叉链表树的二叉链表(孩子孩子-兄弟兄弟)存储表示法存储表示法typedef struct CSNode Elem data; struct CSNode *firstchild, *nextsibling; CSNode, *CSTree;C言语的类型描画言语的类型描画:结点构造结点构造:
48、 firstchild data nextsibling设森林设森林 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。由二叉树转换为森林的转换规那么为由二叉树转换为森林的转换
49、规那么为:假设 B = , 那么 F = ;否那么,由 Node(root) 对应得到 ROOT( T1 );由LBT 对应得到 ( t11, t12, ,t1m);由RBT 对应得到 (T2, T3, , Tn)。 由此,树的各种操作均可对应二由此,树的各种操作均可对应二叉树的操作来完成。叉树的操作来完成。 该当留意的是,和树对应的该当留意的是,和树对应的二叉树,其左、右子树的概念二叉树,其左、右子树的概念已改动为:左是孩子,右是兄弟已改动为:左是孩子,右是兄弟6.7 树和森林的遍历树和森林的遍历树的遍历可有三条搜索途径树的遍历可有三条搜索途径:按层次遍历按层次遍历:先根先根(次序次序)遍历
50、遍历:后根后根(次序次序)遍历遍历: 假设树不空,那么先访问根结点,假设树不空,那么先访问根结点,然后依次先根遍历各棵子树。然后依次先根遍历各棵子树。 假设树不空,那么先依次后根遍历假设树不空,那么先依次后根遍历各棵子树,然后访问根结点。各棵子树,然后访问根结点。 假设树不空,那么自上而下自左假设树不空,那么自上而下自左至右访问树中每个结点。至右访问树中每个结点。 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 I J K H G D A
51、 层次遍历时顶点层次遍历时顶点的访问次序:的访问次序:A B C D E F G H I J K B C DE F G H I J K1. 森林中第一棵树森林中第一棵树的根结点;的根结点;2. 森林中第一棵森林中第一棵树的子树森林;树的子树森林;3. 森林中其它树构森林中其它树构成的森林。成的森林。森林由三部分构成:森林由三部分构成:1. 先序遍历先序遍历 假设森林不空,那么假设森林不空,那么访问森林中第一棵树的根结点访问森林中第一棵树的根结点;先序遍历森林中第一棵树的子树森林先序遍历森林中第一棵树的子树森林;先序遍历森林中先序遍历森林中(除第一棵树之外除第一棵树之外)其其 余树构成的森林。余
52、树构成的森林。即:依次从左至右对森林中的每一棵即:依次从左至右对森林中的每一棵树进展先根遍历。树进展先根遍历。中序遍历中序遍历 假设森林不空,那么假设森林不空,那么中序遍历森林中第一棵树的子树森林中序遍历森林中第一棵树的子树森林;访问森林中第一棵树的根结点访问森林中第一棵树的根结点;中序遍历森林中中序遍历森林中(除第一棵树之外除第一棵树之外)其其 余树构成的森林。余树构成的森林。即:依次从左至右对森林中的每一棵即:依次从左至右对森林中的每一棵树进展后根遍历。树进展后根遍历。先根遍历先根遍历后根遍历后根遍历树树二叉树二叉树森林森林先序遍历先序遍历先序遍历先序遍历中序遍历中序遍历中序遍历中序遍历
53、树的遍历和二叉树遍历的对应关系树的遍历和二叉树遍历的对应关系 ?设树的存储构造为孩子兄弟链表设树的存储构造为孩子兄弟链表typedef struct CSNode Elem data; struct CSNode *firstchild, *nextsibling; CSNode, *CSTree;一、求树的深度一、求树的深度二、输出树中一切从根到叶子的途径二、输出树中一切从根到叶子的途径三、建树的存储构造三、建树的存储构造int TreeDepth(CSTree T) if (!T) return 0; else h1 = TreeDepth( T-firstchild ); h2 = Tr
54、eeDepth( T-nextsibling); / TreeDepthreturn(max(h1+1, h2); A B C DE F G H I J K例如:对左图所示的树,例如:对左图所示的树,其输出结果应为:其输出结果应为:A B EA B FA CA D G H IA D G H JA D G H Kvoid AllPath( Bitree T, Stack& S ) if (T) Push( S, T-data ); if ( !T-lchild & !T-rchild ) PrintStack(S); else AllPath( T-lchild, S ); Al
55、lPath( T-rchild, S ); Pop(S); / if(T)/ 输出二叉树上从根到一切叶子结点的途径输出二叉树上从根到一切叶子结点的途径void OutPath( CSTree T, Stack& S ) while ( T ) Push(S, T-data ); if ( !T-firstchild ) Printstack(s); else OutPath( T-firstchild, s ); Pop(S); T = T-nextsibling; / while / OutPath/ 输出森林中一切从根到叶的途径输出森林中一切从根到叶的途径 和二叉树类似,不同的定义
56、相应有不和二叉树类似,不同的定义相应有不同的算法。同的算法。 假设以二元组假设以二元组(F,C)的方式自上而下、的方式自上而下、自左而右依次输入树的各边,建立树的自左而右依次输入树的各边,建立树的孩子孩子-兄弟链表。兄弟链表。ABCDEFG例如例如:对以下所示树的输入序列应为对以下所示树的输入序列应为: :(#, A)(A, B)(A, C)(A, D)(C, E)(C, F)(E, G)ABCD(#, A)(A, B)(A, C)(A, D)(C, E)可见,算法中需求可见,算法中需求一个队列保管已建一个队列保管已建好的结点的指针好的结点的指针void CreateTree( CSTree
57、&T ) T = NULL; for( scanf(&fa, &ch); ch!= ; scanf(&fa, &ch) p = GetTreeNode(ch); / 创建结点创建结点EnQueue(Q, p); / 指针入队列指针入队列if (fa = ) T = p; / 所建为根结所建为根结点点 else / 非根结点的情况非根结点的情况 / for / CreateTree GetHead(Q,s); / 取队列头元素取队列头元素(指针值指针值)while (s-data != fa ) / 查询双亲结点查询双亲结点 DeQueue(Q,s); GetHead(Q,s); if (!(s-firstchild) s-firstchild = p; r = p; / 链接第一个孩子结点链接第一个孩子结点else r-nextsibling = p; r = p; / 链接其它孩子结点链接其
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026陕西西安交通大学党委医学部文员招聘1人备考题库及答案详解【名校卷】
- 2026河南省人力资源开发中心有限公司招聘5人备考题库含答案详解【综合卷】
- 2026清明上河园招聘备考题库含答案详解(突破训练)
- 2026黑龙江齐齐哈尔市克东县公益性岗位人员招聘60人备考题库【a卷】附答案详解
- 2026浙江国检检测技术股份有限公司第一轮招聘员工5人备考题库含答案详解【夺分金卷】
- 2026四川宜宾珙县总工会第一次招聘社会化工会工作者1人备考题库附完整答案详解【网校专用】
- 2026贵州省旅游产业发展集团有限公司招聘3人备考题库及完整答案详解
- 2026四川自贡市国有资本投资运营集团有限公司招聘1人备考题库含答案详解(预热题)
- 安全生产专项方案
- 海洋工程平台租赁合同协议2025年
- 神州数码集团在线测评题
- 掺混肥料生产管理制度
- 2026年安徽财贸职业学院单招综合素质笔试备考试题附答案详解
- 2026内蒙古事业单位招聘第一阶段减少招聘人数岗位(公共基础知识)测试题附答案
- 胆总管结石课件
- 入孵合同解除协议
- 数据出境安全协议
- 护士交接班礼仪
- 2025年10月自考05677法理学试题及答案含评分参考
- 2025年专升本旅游管理历年真题汇编试卷及答案
- 2026年辽宁医药职业学院单招职业适应性测试必刷测试卷及答案1套
评论
0/150
提交评论