1.38k likes | 1.48k Views
第六章 树与二叉树. 6.1 树的定义和基本术语 6.2 二叉树 6.3 遍历二叉树和线索二叉树 6.4 树和森林 6.5 Huffman 树及其应用. 内蒙古大学. 理工学院. 计算机学院. 生命科学学院. 外国语学院. 人文学院. 数学系. 物理系. 电子系. 日语系. 计算机系. 网络中心. 计算中心. 生物系. 环境系. 动物中心. 生物工程中心. 资源所. 英语系. 汉语系. 历史系. 哲学系. 行政机构. 树形结构是一种非线性结构,应用十分广泛。 如:行政机构、家谱、磁盘目录等. 磁盘目录.
E N D
第六章 树与二叉树 6.1 树的定义和基本术语 6.2 二叉树 6.3 遍历二叉树和线索二叉树 6.4 树和森林 6.5 Huffman树及其应用
内蒙古大学 理工学院 计算机学院 生命科学学院 外国语学院 人文学院 数学系 物理系 电子系 日语系 计算机系 网络中心 计算中心 生物系 环境系 动物中心 生物工程中心 资源所 英语系 汉语系 历史系 哲学系 行政机构 树形结构是一种非线性结构,应用十分广泛。 如:行政机构、家谱、磁盘目录等
叶Leaf 分枝Branch 根Root 6.1 树(Tree)的定义和基本术语 根-----------------根结点 分枝--------------分枝结点 叶-----------------叶结点
6.1 树(Tree)的定义和基本术语 • 树的定义:树是n(n>=0)结点的有限集, 在任意非空树中: (1) 有且仅有一个特定的结点称为根(Root)的结点. (2) 当n>1时,其余的结点可分为m个互不相交的子 集 T1, T2, … , Tm, 每个子集又都是树,称为根 的子树(Sub tree). 树的定义具有递归性
Book C1 C2 C3 Chapter S1.1 S1.2 S2.1 S2.2 S2.3 Section S2.1.1 S2.1.2 Section 6.1 树(Tree)的定义和基本术语 例6.1 Tree=<D, {R}> D={Book, C1, C2, C3, S1.1, S1.2, S2.1, S2.2, S2.3, S2.1.1, S2.1.2 } R={<Book,C1>, <Book,C2>, <Book,C3>, <C1,S1.1>, <C1,S1.2>, <C2,S2.1>, <C2,S2.2>, <C2,S2.3>, <S2.1, S2.1.1>, <S2.1, S2.1.2>}
6.1 树(Tree)的定义和基本术语 • 术语主要来源于家谱和树: 双亲、父母( Parent);子女、孩子(Child): 若〈a,b〉 R,则称a是b的双亲,b是a 的子女(孩子). 叶结点(Leaf):度为0的结点; 分枝结点(Branch node):度大于0的结点; 结点度(Degree):该结点所拥有的子女数; 树的度:树内各结点度的最大值; 结点的层次(Level):设根结点的层次为1,其它任一结点 所在的层次是其双亲的层次加1;
6.1 树(Tree)的定义和基本术语 • 树是一种层次结构 (hiberarchy) 1 2 3 4 5
无序 A A B C C B 有序 6.1 树(Tree)的定义和基本术语 深度(Depth):树中结点的最大层次;或称为高; 兄弟(Sibling):具有同一双亲的结点互称兄弟; 堂兄弟(Cousin):双亲在同一层的结点之间互称堂兄弟; 路径(Path):如果有结点序列n1,n2,n3,…,nk,并且前1个结 点是后1个结点的双亲;它的长度是k-1; 祖先、后代(ancestor):一个结点是它所有子树中的结点 的祖先,这些结点是它的后代(子孙); 有序树(Ordered tree):每个结点的子女由左到右是有次 序的称有序树;否则是无序树;
A B C D E F G H I J K L M 结点A的度:3 结点B的度:2 结点M的度:0 叶子:K,L,F,G,M,I,J 结点I的双亲:D 结点L的双亲:E 结点A的孩子:B,C,D 结点B的孩子:E,F 结点B,C,D为兄弟 结点K,L为兄弟 树的度:3 树的深度:4 结点A的层次:1 结点M的层次:4 结点F,G为堂兄弟 结点A是结点F,G的祖先
root F A B C D E F G H I J K L M 6.1 树(Tree)的定义和基本术语 • 森林(Forest):是m(m 0)棵互不相交的树的集合 T1 T2 T3 T4 T5 T6 (例如删除树根后的子树构成一个森林) 任何一棵非空树是一个二元组Tree = (root,F) 其中:root 被称为根结点,F 被称为子树森林
6.1 树(Tree)的定义和基本术语 • 抽象数据类型树的定义: ADT Tree{ 数据对象D:D是具有相同特性的数据元素的集合。 数据关系R:若D为空集,则称为空树; 若D仅含一个数据元素,则R为空集,否则R={H},H是如下二元关系: (1) 在D中存在唯一的称为根的数据元素root,它在关系H下 无前驱; (2) 若D-{root}≠ ,则存在D-{root}的一个划分D1,D2, …,Dm,(m>0),对任意j≠k(1≤j,k≤m)有Dj∩Dk= , 且对任意的i(1≤i≤m),唯一存在数据元素xi∈Di, 有<root,xi>∈H;
(3) 对应于D-{root}的划分,H—{<root,x1>,…,<root,xm>} 有唯一的一个划分H1,H2,…,Hm(m>0),对任意j≠k(1≤j, k≤m) 有Hj∩Hk= ,且对任意i(1≤i≤m),Hi是Di上的二元 关系,(Di,{Hi})是一棵符合本定义的树,称为根root的子树. 基本操作: InitTree(&T) 操作结果:构造空树T。 DestroyTree(&T) 初始条件:树T存在。 操作结果,销毁树T。
基本操作: CreateTree(&T,definition) 初始条件:definition给出树T的定义。 操作结果:按definition构造树T。 ClearTree(&T) 初始条件;树T存在。 操作结果:将树T清为空树。 TreeEmpty(T) 初始条件:树T存在。 操作结果:若T为空树,则返回TRUE,否则FALSE。 TreeDepth(T) 初始条件:树T存在。 操作结果;返回T的深度。
基本操作: Root(T) 初始条件:树T存在。 操作结果:返回T的根。 Value(T,cur_e) 初始条件:树T存在,cur_e是T中某个结点。 操作结果:返回cur_e的值。 Assign(T,cur_e,value) 初始条件:树T存在,cur_e是T中某个结点。 操作结果:结点cur_e 赋值为value。 Parent(T,cur_e); 初始条件:树T存在,cur_e是T中某个结点。 操作结果:若cur_e是T的非根结点,则返回它的双亲, 否则返回“空”。
基本操作: LeftChild(T,cur_e); 初始条件:树T存在,cur_e是T中某个结点。 操作结果:若cur_e是T的非叶子结点,则返回它的 最左孩子,否则返回“空”。 RightSibling(T,cur_e); 初始条件:树T存在,cur_e是T中某个结点。 操作结果:若cur_e有右兄弟,则返回它的右兄弟, 否则返回“空”。
基本操作: InsertChild(&T,&P,i,c); 初始条件:树T存在,p指向T中某个结点,i指结点的度, 非空树c与T不相交。 操作结果:插入c为T中p所指结点的第i棵子树。 DeleteChild(&T,&p,i); 初始条件:树T存在,p指向T中某个结点,i指结点的度, 操作结果:删除T中p所指结点的第i棵子树。 TraverseTree(T); 初始条件;树T存在。 操作结果:按某种次序对T的每个结点进行遍历。 }ADT Tree
A B C D E F G H I J (A(B(E))(C(F))(D(G(H)(I)(J)))) 树根 T2 T1 T3 6.1 树(Tree)的定义和基本术语 • 树的表示方法: • 1. 树形表示: 2. 括号表示(广义表表示):
A B E C A F D G B C D H I E F G J H I J 6.1 树(Tree)的定义和基本术语 3. 凹入表表示(目录表示法):
A A D C G B C D F B E H I J E F G H I J 6.1 树(Tree)的定义和基本术语 4. 文氏图表示(集合表示):
6.2 二叉树(Binary Tree) 二叉树是另一种树形结构。 6.2.1 二叉树的定义 二叉树:是n(n>=0)结点的有限集,在任意非空树中: (1) 有且仅有一个特定的称为根(Root)的结点; (2) 当n>1时,其余的结点最多分为2个互不相交的子集 T1, T2, 每个又都是二叉树,分别称为根的左子树和右子树.
根结点 A 右子树 B E F C G D 左子树 H K 6.2.1 二叉树的定义 例 二叉树
注意:二叉树不是树,它是另外单独定义的一种树形结构,并非一般树的特例。它的子树有顺序规定,分为左子树和右子树。不能随意颠倒。注意:二叉树不是树,它是另外单独定义的一种树形结构,并非一般树的特例。它的子树有顺序规定,分为左子树和右子树。不能随意颠倒。
1 空 2 只有根 3 右子树空 4 左子树空 5 左、右子树非空 二叉树的5种基本形态: 具有3个结点的二叉树可能有几种不同形态?
6.2.1 二叉树的定义 抽象数据类型二叉树的定义: ADT BinaryTree{ 数据对象D:D是具有相同特性的数据元素的集合。 数据关系R: 若D= ,则R= , 称Binary为空二叉树; 若D≠ ,则R={H},H是如下二元关系: (1) 在D中存在唯一的称为根的数据元素root,它在关系H下无前驱; (2) 若D-{root}≠ ,则存在D-{root}的一个划分{Dl,Dr},且Dl∩Dr= ; (3)若Dl≠ ,则Dl中存在唯一的元素x1,<root,x1> H, 且存在Dl上的关系HlH,若Dr ≠ ,则Dr中存在唯一的元素xr,<root,xr> H,且存在Dr上的关系HrH;H={<root,xl>,<root,xr>,Hl,Hr} (4)(Dl,{Hl})是一颗符合本定义的二叉树,称为根的左子树 (Dr,{Hr})是一颗符合本定义的二叉树,称为根的右子树
基本操作: InitBiTree(&T); 操作结果:构造空二叉树T。 DestroyBiTree(&T); 初始条件:二叉树T存在。 操作结果:销毁二叉树T。 CreatBiTree(&T,definition); 初始条件:definition给出二叉树T的定义。 操作结果:按definition构造二叉树T。 ClearBiTree(&T); 初始条件:二叉树T存在。 操作结果:将二叉树T清为空树。
基本操作: BiTreeEmpty(T); 初始条件:二叉树T存在。 操作结果:若T为空二叉树,则返回TRUE,否则FALSE. BiTreeDepth(T); 初始条件:二叉树T存在。 操作结果:返回T的深度。 Root(T); 初始条件: 二叉树T存在。 操作结果:返回T的根。 Value(T,e) 初始条件:二叉树T存在,e是T中某个结点。 操作结果;返回e的值。
基本操作: Assign(T,&e,value); 初始条件;二叉树T存在,e是T中某个结点。 操作结果:结点e赋值为value。 Parent(T,e); 初始条件:二叉树T存在,e是T中某个结点。 操作结果:若e是T的非根结点,则返回它的双亲,否则返回“空”。 LeftChild(T,e); 初始条件:二叉树T存在,e是T中某个结点。 操作结果:返回e的左孩子,若e无左孩子,则返回“空”。 RightChild(T,e); 初始条件:二叉树T存在,e是T中某个结点。 操作结果:返回e的右孩子,若e无右孩子,则返回“空”。
基本操作: LeftSibling(T,e); 初始条件:二叉树T存在,e是T中某个结点。 操作结果:返回e的左兄弟。若e是T的左孩子或无左兄弟,则 返回“空”。 Rightsibling(T,e); 初始条件:二叉树T存在,e是T中某个结点。 操作结果:返回e的右兄弟。若e是T的右孩子或无右兄弟, 则返回“空”。
基本操作: InsertChild(T,p,LR,c); 初始条件:二叉树T存在,p指向T中某个结点,LR为0或1, 非空二叉树c与T不相交且右子树为空。 操作结果:根据LR为0或1,插入c为T中p所指结点的左或 右子树。P所指结点的原有左或右子树则成为c 的右子树。 DeleteChild(T,p,LR); 初始条件:二叉树T存在,p指向T中某个结点,LR为0或1。 操作结果:根据LR为0或1,删除T中p所指结点的左或右子树。
基本操作: PreOrderTraverse(T); 初始条件:二叉树T存在。 操作结果:先序遍历T中对每个结点一次且仅一次。 InOrderTraverse(T); 初始条件:二叉树T存在。 操作结果:中序遍历T中每个结点一次且仅一次。
基本操作: PostOrderTraverse(T); 初始条件:二叉树T存在。 操作结果:后序遍历T中每个结点一次且仅一次。 LevelOrderTraverse(T); 初始条件:二叉树T存在。 操作结果:层序遍历T中每个结点一次且仅一次. }ADT BinaryTree
6.2.2 二叉树的性质 性质1: 在二叉树的第i层最多有2i-1个结点(i>=1). 用归纳法证明: 归纳基: 归纳假设: 归纳证明: i = 1层时,只有一个根结点, 2i-1 = 20 = 1; i=k时命题成立; i=k+1时,二叉树上每个结点至多有两棵子树,则第 i 层的结点数 = 2k-1 2 = 2(k+1)-1=2i-1。
6.2.2 二叉树的性质 性质2: 深度为k的二叉树最多有2k –1个结点(k>=1). 证明: 基于性质1,深度为 k 的二叉树上的结点数最多为 20+21+ +2k-1 = 2k-1
6.2.2 二叉树的性质 性质3: 任一二叉树, 若叶结点数是n0 , 度为2的结点数 是 n2 ,则 n0 = n2 +1 证明: 设 二叉树上结点总数 n = n0 + n1 + n2 又 二叉树上分支总数 b = n1+2n2 而 b = n-1 = n0 + n1 + n2 - 1 由此, n0 = n2 + 1
1 A 2 B 3 C D 4 E 5 H 6 F 7 编号的满二叉树 6.2.2 二叉树的性质 满二叉树(Full Binary Tree): 每一层的结点数都达到了最 大的二叉树. 编号的满二叉树: 从根开始,由上到下, 从左到右地对每个结点 进行编号. 也就是说:根的编号是1,一个结点,若它是双亲 的左子女,则它的编号是它的双亲编号的2倍;若它是双亲 的右子女,则它的编号是双亲编号的2倍+1.
1 A 1 A 1 A 2 B 3 C 3 2 B C 2 3 B C F 7 4 E 5 H 6 F 4 D E 5 4 E 6.2.2 二叉树的性质 完全二叉树(Complete Binary Tree): 深度为k的满二叉树, 删去第k层上最右边的j(0 j<2k-1)个结点,就得到一个深度为k 的完全二叉树. 编号的完全二叉树: 与满二叉树编号相同
设 完全二叉树的深度为 k 则根据性质2得 2k-1 -1 < n ≤ 2k-1 或者 2k-1 ≤ n < 2k 即 k-1 ≤log2 n <k 因为 k 只能是整数,因此, k =log2n+ 1 或 k = log2n+1 6.2.2 二叉树的性质 性质4: 具有n个结点的完全二叉树,其深度为 。 证明:
6.2.2 二叉树的性质 性质5:在编号的完全二叉树中,对任一结点i(1≤i ≤ n)有: (1)若i=1, 是根; 若i>1,则它的双亲是 (2)若2i ≤ n,则结点i的左子女是2i; 否则无左子女; (3)若2i+1 ≤ n,则结点i的右子女是2i; 否则无右子女; 1 2 3 i i+1 4 5 6 2i 2i+1 2i+2
1 A 2 B 3 C 4 E 5 H 6 F 6.2.3 二叉树的存储结构 一 、二叉树的顺序存储 完全二叉树的顺序存储: 0 1 2 3 4 5 6 A B C E H F ST[ ] 根据性质5知: ST[i] 的双亲是ST[ ], 左子女是ST[2*i],右子女是ST[2*i+1].
1 A 2 B 3 C 4 E F 7 9 H 6.2.3 二叉树的存储结构 一、二叉树的顺序存储 0 1 2 3 4 5 6 7 8 9 A B C E F H ST[ ] 根据性质5知: ST[i] 的双亲是ST[ ], 左子女是 ST[2*i],右子女是ST[2*i+1]. 这样太浪费空间,适合完全二叉树
BiTNode: lchild data rchild Left child Right child A A BT B C B C E H F E H F G G 二叉链表 6.2.3 二叉树的存储结构 二、 二叉树的链式存储结构(二叉链表) typedef struct BiTNode{ ElemType data; struct BiTNode *lchild,* rchild; }BiTNode, *BiTree;
6.2.3 二叉树的存储结构 二 、二叉树的链式存储结构(三叉链表) BiTNode: typedef struct BiTNode{ ElemType data; struct BiTNode *lchild,*rchild,*parent; }BiTNode, *BiTree; Parent lchild data rchild parent Left child Right child
BT A A B C B C E H F E H F G G 三叉链表 6.2.3 二叉树的存储结构 二 、二叉树的链式存储结构(三叉链表)
6.3 遍历二叉树和线索二叉树 一、遍历 按照某种搜索路径访问二叉树中的所有结点,使得每个结点被访问一次且仅被访问一次。 “访问”的含义特别很广,如:输出结点的信息等。 因二叉树是非线性结构, 每个结点可能有两个后继,则存在如何遍历即按什么样的搜索路径遍历的问题。
6.3 遍历二叉树和线索二叉树 二、遍历方法 NLR LNR LRN 前(先)序 遍历 1 中序遍历 N 3 后序遍历 2 NRL RNL RLN L R
6.3 遍历二叉树和线索二叉树 算法思想6.1 前序遍历: 若BT非空,则: 1.访问根结点; 2.前序遍历左子树; 3.前序遍历右子树; 算法思想6.2 中序遍历: 若BT非空,则: 1.中序遍历左子树; 2.访问根结点; 3.中序遍历右子树; 算法思想6.3 后序遍历: 若BT非空,则: 1.后序遍历左子树; 2.后序遍历右子树; 3.访问结点;
6.3 遍历二叉树和线索二叉树 例6 A A A A 算法思想6.1 前序遍历: 若BT非空,则: 1.访问根结点; 2.前序遍历左子树; 3.前序遍历右子树; B B B B C C C C E E E E H H H H F F F F G G G G 前序遍历(NLR)序列: A B E H G C F 中序遍历(LNR)序列: E B G H A F C 后序遍历(LRN)序列: G H B F C A E
前序遍历二叉树的递归算法 算法 6.1 Void PreOrderTraverse(BiTree BT){ if (BT){ visit(BT); PreOrderTraverse(BT->lchild); PreOrderTraverse(BT->rchild); }// } // end of PreOrderTraverse 请同学们自己写出 InOrderTraverse(BT) 和 PostOrderTraverse(BT)
A B C D E F 建立二叉树 建立二叉树的方法很多,我们给出以前序遍历序列建 立二叉树的方法,但该序列是扩充二叉树的前序遍历 序列。 是扩充的叶结点,它代表空指针。 该扩充二叉树的前序遍历序列是:ABD**EF***C** 该算法是一递归算法,递归三要素: 1. 递归出口:当遇到*时,是空。 2. 建立根。 3. 建立左子树和右子树。