230 likes | 446 Views
第六章 树和二叉树. 树的定义和基本术语 二叉树的定义、性质和存储结构 遍历二叉树(编程) 树和森林 赫夫曼树及其编码. 第六章 树和二叉树. 树的定义和基本术语 树( tree) 是 n(n>=0) 个结点的有限集。在任意一棵非空树中:(1)有且仅有一个特定的称为根( root) 的结点;(2)当 n>1 时,其余结点可分为 m(m>0) 个互不相交的有限集 T1,T2 …… Tm, 其中每一个集合本身又是一棵树,称为根的子树。 树的基本操作 建树 求孩子结点 求根结点 求兄弟结点 求双亲结点 结点的插入、删除. 第六章 树和二叉树.
E N D
第六章 树和二叉树 • 树的定义和基本术语 • 二叉树的定义、性质和存储结构 • 遍历二叉树(编程) • 树和森林 • 赫夫曼树及其编码
第六章 树和二叉树 • 树的定义和基本术语 • 树(tree)是n(n>=0)个结点的有限集。在任意一棵非空树中:(1)有且仅有一个特定的称为根(root)的结点;(2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1,T2……Tm,其中每一个集合本身又是一棵树,称为根的子树。 • 树的基本操作 • 建树 求孩子结点 • 求根结点 求兄弟结点 • 求双亲结点 结点的插入、删除
第六章 树和二叉树 • 树的表示形式 • 树形表示 • 嵌套集合表示 • 广义表表示 • 凹入表表示 • 基本术语 • 树的结点——指一个数据元素及若干指向其子树的分支。通常以结构体来描述。 • 结点的度——结点拥有的子树数。度为0的结点称为叶子或终端结点;度不为0的结点称为非终端结点或分支结点。
第六章 树和二叉树 • 树的度——树内各结点度的最大值。 • 孩子和双亲——结点的子树的根为该结点的孩子,该结点为孩子的双亲。 • 结点的层次——根为第一层,依次类推。 • 兄弟和堂兄弟——双亲相同的结点为兄弟,双亲在同一层次的结点为堂兄弟。 • 祖先和子孙——从根到该结点所经分支上的所有结点为该结点的祖先;以某结点为根的子树中的任一结点都称为该结点的子孙。 • 树的深度(高度)——树中结点的最大层次。
第六章 树和二叉树 • 有序树和无序树——如果将树中结点的各子树看成从左到右是有次序的(即不能交换),则称该树为有序树,否则为无序树。 • 森林——是m(m>=0)个棵互不相交的树的集合。 • 二叉树 • 二叉树的定义 • 二叉树的每个结点至多只有二棵子树(即二叉树中不存在度大于2的结点),且二叉树的子树有左右之分,其次序不能任意颠倒(有序树)。
第六章 树和二叉树 • 二叉树的基本操作 建树(空树、非空树) 求根结点、双亲、孩子、兄弟结点 二叉树的遍历 插入、删除 • 二叉树的五种基本形态 空二叉树 仅有根结点的二叉树 左子树为空的二叉树 右子树为空的二叉树 左、右子树均非空的二叉树
第六章 树和二叉树 • 二叉树的性质 • 在二叉树的第i层上至多有2i-1个结点(i>=1) • 深度为k的二叉树至多有2k-1个结点(k>=1) • 对任何一棵二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2+1 • 一棵深度为k且有2k-1个结点的二叉树称为满二叉树,其每一层上的结点数都是最大结点数。可以对满二叉树的结点进行连续编号,约定编号从根结点起,自上而下,自左至右。深度为k的,有n个结点的二叉树,当且仅当其每个结点都与深度为k的满二叉树中编号从1至n结点一一对应时,称之为完全二叉树。
第六章 树和二叉树 • 具有n个结点的完全二叉树的深度为 k=[log2n]+1 • 如果对一棵有n个结点的完全二叉树的结点按层序编号,则对任一结点i(i<=1<=n) (1)i=1,结点i为二叉树的根;若i>1,则双亲结点是[i/2] (2)如果2i>n,则结点无左孩子;否则其左孩子是结点2i。 (3)如果2i+1>n,则结点无右孩子;否则其右孩子是结点2i+1。
第六章 树和二叉树 • 二叉树的存储结构 • 顺序存储结构 用一组地址连续的存储单元依次自上而下、自左至右存储完全二叉树上的结点元素,即完全二叉树上编号为i的结点存储在一维数组中下标为i-1的分量中。对一般二叉树,顺序存储结构必须能反映结点之间的逻辑关系(父子关系),故将其每个结点与完全二叉树相 对照进行存储。 这种顺序存储结构仅适用于完全二叉树。最坏情况下,k个结点、深度为k的二叉树需要2k-1个结点的存储空间。
第六章 树和二叉树 • 链式存储结构——头指针指向根结点。 二叉链表——存储结点的一个数据元素和分别指向其左、右子树的两个指针。 三叉链表——增加一个指向双亲结点的指针域。 typedef struct tnode {int data; struct tnode *lchild, *rchild; }TNODE; TNODE *root; 在n个结点的二叉链表中有n+1个空链域。 • 建立二叉树(p131算法6.4)
作业一 • 已知一棵树边的集合为{(i,m),(i,n),(e,i),(b,e),(b,d),(a,b),(g,j),(g,k),(c,g),(c,f),(h,l),(c,h),(a,c)},画出该树的树形表示,并指出该树的根,叶子结点,f的双亲、孩子、祖先,树的深度,树的度。 • 分别画出具有三个结点的树和具有三个结点的二叉树的所有不同形态。
第六章 树和二叉树 • 遍历二叉树和线索二叉树 • 遍历二叉树 • 遍历二叉树是指如何按某条搜索路径巡访树中的每个结点,使得每个结点均被访问一次,而且仅被访问一次。(即将二叉树的结点排成一个线性队列) • 一棵非空二叉树是由根结点、左子树和右子树三个基本部分组成,依次遍历这三部分,便能遍历整个二叉树。若限定先左(L)后右(R),则遍历方法有先序遍历(DLR)、中序遍历(LDR)和后序遍历(LRD)三种。
第六章 树和二叉树 • 先序遍历二叉树的递归算法 访问根->先序遍历左子树->先序遍历右子树 void preorder(TNODE *bt) { if (bt!=NULL) {printf(“%d ”,bt->data); preorder(bt->lchild); preorder(bt->rchild);}} • 中序遍历二叉树的递归算法(inorder) 中序遍历左子树->访问根->中序遍历右子树 • 后序遍历二叉树的递归算法(postorder) 后序遍历左子树->后序遍历右子树->访问根
第六章 树和二叉树 • 表达式的前缀表示(波兰式)、中缀表示和后缀表示(逆波兰式)。 • 将表达式表示为二叉树,若表达式=xy,则根结点存放运算符,左子树表示x,右子树表示y。 a+b*(c-d)-e/f 波兰式:表达式二叉树的前序 中缀表示:中序 逆波兰式:后序 • 从递归执行过程的角度先序、中序和后序是完全相同的。
第六章 树和二叉树 • 线索二叉树 • 遍历二叉树实质上是对一个非线性结构进行线性化操作,使得每个结点有且仅有一个前趋和后继。但以二叉链表作为存储结构时,只能找到结点的左右儿子信息,而没有前趋和后继的信息。由于在n个结点的二叉链表中必定存在n+1个空链域,可以利用空链域存放结点的前趋和后继的信息。 • 二叉链表的指针域描述儿子或前趋后继信息的链表为线索链表;指向前趋和后继的指针为线索;加上线索的二叉树为线索二叉树。对二叉树以某种次序遍历使其变为线索二叉树的过程为线索化。
第六章 树和二叉树 • Typedef struct btnode {char data; struct btnode *lchild, *rchild; int ltag, rtag; }BTNODE; ltag=0 lchild指示结点的左儿子 ltag=1 lchild指示结点的前趋 rtag=0 lchild指示结点的右儿子 rtag=1 lchild指示结点的后继
第六章 树和二叉树 • 树和森林 • 树的存储结构 • 双亲表示法 用一组地址连续的空间存放树中的结点,每个结点存放本身的信息和双亲结点所在的位置序号。 • 孩子表示法 • 多重链表——每个结点有多个指针域,分别指向其每个子树。同构或不同构。 • 孩子链表 ——每个结点有一个孩子链表,n个结点链表的头指针顺序存储。 • 孩子双亲表示法——双亲表示和孩子链表表示法结合起来。
第六章 树和二叉树 • 孩子兄弟表示法——二叉链表表示法***** 二叉链表作为树的存储结构,链表中的两个指针域分别指向该结点的第一个孩子和该结点的下一个兄弟。 • 树、森林与二叉树的转换 • 以二叉链表作为转换的依据。 • 树转化成二叉树后,二叉树根一定没有右子树。 • 森林的第二棵树树根看成是第一棵树树根的兄弟。
第六章 树和二叉树 • 树与森林的遍历 • 树的先序遍历是指先访问树的根结点,然后依次先序遍历根的各子树。等价于先序遍历该树对应的二叉树。 • 树的后序遍历是指先依次后序遍历树的根结点的各子树,然后访问根结点。等价于中序遍历该树对应的二叉树。 • 先序遍历森林是指从左到右依次按先序遍历森林中的每一棵树,相当于先序遍历该森林对应的二叉树。 • 后序遍历森林是指从左到右依次按后序遍历森林中的每一棵树,相当于中序遍历该森林对应的二叉树。
第六章 树和二叉树 • 赫夫曼树及其应用 • 最优二叉树——赫夫曼树 从树中一个结点到另一个结点之间的分支构成这两个结点之间的路径,路径上的分支数目称做路径长度。树的路径长度是从树根到每一结点的路径长度之和。结点的带权路径长度为从该结点到树根之间的路径长度与结点上权的乘积。树的带权路径长度为树中所有叶子结点的带权路径长度之和,记作WPL。 假设有n个权值{w1,w2,…,wn},试构造一棵有n个叶子结点的二叉树,每个叶子结点带权为wi,则其中带权路径长度WPL最小的二叉树称做最优二叉树或赫夫曼树。
第六章 树和二叉树 • 赫夫曼算法——构造赫夫曼树 • 根据给定的n个权值构成n棵二叉树的集合F,每棵二叉树Ti只有一个带权为wi的根结点。 • 在F中选取两棵根结点的权值最小的树作为左右子树构造一棵新二叉树,其根结点的权值为左右子树根结点的权值之和。 • 在F中删除这两棵树,将新二叉树加入F • 重复构造,直到 F中只含一棵树为止,这棵树就是赫夫曼树。
第六章 树和二叉树 • 赫夫曼编码——电报码 • 电文的总长尽可能短——出现次数多的字符采用尽可能短的编码。 • 任一个字符的编码都不是另一个字符编码的前缀——前缀编码。 • 设计电文总长最短的二进制前缀编码即为以n种字符出现的频率作权,设计一棵赫夫曼树的问题。 • 约定赫夫曼树的左分支表示字符‘0’,右分支表示字符‘1’,从根结点到叶子结点的路径上分支字符组成的字符串作为该叶子结点字符的编码。
作业二 • 先序、中序、后序遍历二叉树。 • 将下列表达式用二叉树表示,写出其波兰式和逆波兰式。(a-b)/(c*d+s)+e*g/f(x+y*z)-h*(t+q) • 已知一棵二叉树的中序序列为BDCEAFHG,后序序列为BECDHGFA,画出这棵二叉树,并前序遍历。 • 将树转化成对应的二叉树。 • 将二叉树转换成森林,对森林进行两种遍历。 • 假设通讯电文中仅由13个字母组成,字母在电文中出现的频率分别为7,13,2,6,12,8,4,22,3,13,4,6,试为这13个字母设计哈夫曼编码。