知识要点:
树的结构和主要概念,各种二叉树的结构及其特点;
二叉树的三种遍历方法的实现原理和性质,能将二叉树的遍历方法应用于求解二叉树的叶子结点个数、二叉树计数等问题,遍历的非递归实现方法;
线索化二叉树的结构和基本操作;(充分利用二叉树的空链域)
森林的定义和存储结构,森林的遍历等方法的实现;(遍历方式与二叉树一致)
基于霍夫曼树生成霍夫曼编码的方法;
最优二叉树(霍夫曼树)的构造原理和相关算法。
AVL树的定义和特点以及AVL树调整操作的实现原理;(平衡二叉树的创建与调整)
1、树
树的定义:含有n个结点的有限集合;n=0时二叉树为空树;
1)在非空二叉树 中有且只有一个被称为根的结点;
2)其余结点可以分为多个互不相交的集合,每个集合本身又是一棵树;
特点:除了根结点之外,每个结点都有前驱结点,树中所有结点可以有0个或多个后继结点。
对于含有n个结点的树,其有n-1条边;
树的相关定义(了解):
祖先结点:沿着某一路径到达结点K,K之前的所有结点都为其祖先结点;
子孙结点:从K点沿着某一路径向下,K之后的所有结点都为其子孙结点;
双亲结点:在K结点上侧,且直接与K相互关联的结点,称为K的双亲结点;
孩子结点:在K结点下侧,且直接与K相互关联的结点,称为K的孩子结点;
兄弟结点:位于同一层次上,且双亲结点相同的结点之间互为兄弟结点;
结点的度:该结点所具有的分支数;(由此结点发出的边的条数)
树的度:树中结点度的最大值;
分支结点:度非0的结点,所具有的分支数就是该结点的度;
叶子结点(终端结点):度为0的结点;
结点的层次:根结点位于第一层,由上往下层次数依次加一;
树的高度(深度):结点的最大层次数;
有序树和无序树:不区分子树的先后顺序为无序树(子树可以相互交换位置),反之称为有序树;
路径和路径长度:两个结点之间的路径即结点之间所经过的分支,分支的数目称为路径长度;
森林:多颗互不相交的树的集合;
性质:树中的结点数等于所有结点的度数加1(含有n个结点的树边数为n-1)
树中有n-1条边,所有结点的度数为n-1 ->此树中含有n个结点
m叉树中中第i层最多有m^(i-1)个结点;
第一层1个,第二程m个,第三层m^2个,数学归纳法得出第i层最多有m^(i-1)个
树高为h的m叉树最多有(m^h-1)/(m-1)个结点;
1+m+m^2+.....+m^(h-1) 等比数列求和
含有n个结点的m叉树的最小高度为 logm[n(m-1)+1]上取整;
让每一层都达到最大结点数,所形成的树高度最小;
(m^h-1)/(m-1)>=n且(m^(h-1)-1)/(m-1) logm[n(m-1)+1]<=h 二叉树的定义:(递归定义且为有序树子树之间不能相互变化) 要么为空树,要么满足以下定义: 1)有且只有一个被称为根的结点; 2)除了根结点之外,其余结点又分为两个互不相交的集合,每个集合又满足二叉树的定义(左右子树); 性质:叶子节点的个数等于度为2的结点个数+1(即 N0=N2+1) N0+N1+N2=N; N1+2N2=N-1;联立两式得出N0=N2+1; 含有n个结点的二叉树必有n+1个空指针域(可以用于二叉树的线索化); N2=N0-1;N0+N1+N2=n;得出N1+2N0=n+1;(N0提供两个空指针域,N1提供一个空指针域) 两种特殊的二叉树:(完全二叉树和满二叉树) 满二叉树:每一层的结点数都达到最大值(即深度为k的二叉树结点数目为2^k-1,每i层结点为2^(i-1)) 完全二叉树:对二叉树从根开始由右到左依次标号,与满二叉树对应的标号一致则称之为完全二叉树; 特点:叶子结点只会出现在层次最大的两层上; 性质:含有n个结点的完全二叉树的深度为,k=(log2[n])(下取整)+1; 完全二叉树中要么无度为1的结点,要么有且只有一个度为1的结点,而且此结点一定无右孩子; 完全二叉树由上至下,由左往右对结点进行依次编号(i=1时为根结点) 1)当i>1时,其双亲结点的值为(i/2) 2)2*i<=N时,其左孩子编号为2i,否则无左孩子 3)2*i+1<=N时,其左孩子编号为2*i,右孩子编号为2*i+1,否则无右孩子; 二叉树的四种遍历方式(先序、中序、后序、层次) 先序遍历:根->左->右;中序遍历:左->根->右;中序遍历:左->右->根;层次遍历:由上到下,由左到右; 已知中序和其他的任意一种遍历方式既可以唯一确定一颗二叉树; 二叉树的前三种遍历方式满足递归定义,通过递归可以实现(借助栈结构),层次遍历需要借助队列实现; 二叉树的存取方式(顺序存储、链式存储):顺序存取需要开辟一连续内存空间,会有空间上的浪费;对于链式存取 设立左右指针域,标明左右子树关系; 线索二叉树(充分利用空指针域来表明遍历的前驱和后继)方便直接找到遍历前驱与后继,加快查找速度 根据遍历的顺序确定当前结点的前驱和后继;(左前驱,右后继) ltag=0时,表示该结点有左孩子,左指针域指向左孩子结点; ltag=1时,表示该结点无左孩子,左指针域指向此结点的前驱结点; rtag=0时,表示该结点有右孩子,右指针域指向右孩子结点; rtag=1时,表示该结点无右孩子,左指针域指向此结点的后继结点; 总结:0表示该结点有对应的孩子,1表示该结点指针域为NULL,指向其前驱和后继; 树的表示方法:双亲表示法、孩子表示法、孩子兄弟法(左孩子右兄弟)根结点的右指针域为NULL; ☆☆☆树与森林的转化: 二叉树转化成树: 二叉树转化成森林: 1、断开从根结点沿着右下角路径上的所有连线。 树、二叉树、森林转化的总结: 1、树转化为二叉树:连接所有的兄弟结点,去除除了第一个结点之外的其他与父节点的连线, 以根为轴心顺时针旋转45度; (二叉树转化为树与之相反) 2、森林转化为二叉树:将森林中的每一颗树转化成二叉树。 连接新生成二叉树的每一个根结点(第一颗树的根结点为生成二叉树的树根,有指针域指向第二颗子树,依次类推); 以根为旋转轴顺时针旋转45度; 3、二叉树转化为森林:断开从根结点开始一直向右下方的所有连线,生成多颗二叉子树, 将每颗二叉子树转化成树即可构成森林; 树、森林、二叉树的遍历之间的关系: 哈夫曼树(哈夫曼编码):左零右一,哈夫曼编码为最优前缀编码,叶子结点保存数据 前缀编码:任何一个编码都不是另一个编码的前缀则此编码称为前缀编码; 哈夫曼树为带权路径长度最小的树,其树形并不唯一,但所求权值一定相同; ☆☆☆哈夫曼树的构造:(左0右1) 1)有N个结点各自为根形成一个集合(森林) 2)从集合中选取最小的两个值作为叶子结点,生成一颗新树,此树根结点的权值为叶子结点的权值之和; 如果权值相同,优先选用高度最小的;将原树结点删除,将新生成的树加入集合(森林)中; 3)重复2步骤直到森林中只有一颗树,该树就为哈夫曼树; 二叉排序树(BST):要么为一颗空树,要么满足一下定义(递归定义) 1)左子树非空,则左子树中任意结点的值小于根节点的值; 2)右子树非空,则右子树中任意结点的值大于根结点的值; 3)左右子树又满足一颗二叉排序树的定义; 特点:中序遍历得到的是一个有序序列。对于二叉排序树的查找最优时间复杂度为O(log2n),最坏为单支树的情况O(n); 所以二叉排序树的查找效率与树形(高)有关;若本身插入的构造数据有序,则此二叉排序树为单支树; 二叉排序树的删除:1)如果是叶子结点则直接删除;(不影响二叉排序树的性质) 2)如果为非叶子结点且只有一颗左或右子树,则直接让子树的根结点代替原删除结点即可; 3)如果为非叶子结点且有左右子树,则让子树中的子女位置填充删除结点的位置; 比如右子树中最左侧的结点或者左子树中最右侧的结点; 平衡二叉树: 定义:要么为空树,要么满足一下定义; 每个结点的左右子树的深度之差(平衡因子)的绝对值不超过1;(平衡因子只能是-1,0,1) ☆☆☆重点:对于平衡二叉树的调整:(左逆右顺,负负得正) LL型:在A结点左子树根结点的左子树插入结点,导致A结点平衡因子由1变2 进行一次顺时针旋转;将原根结点的左孩子作为新生成树的根结点,将左孩子的右子树作为原树根结点的左孩子。 RR型:在A结点右子树根结点的右子树插入结点,导致A结点平衡因子由-1变-2 进行一次逆时针旋转;将原根结点的右孩子作为新生成树的根结点,将右孩子的左子树作为原树根结点的右孩子。 LR型:在A结点左子树根结点的右子树插入结点,导致A结点平衡因子由1变2 先逆时针旋转一次,后顺时针旋转一次; 将新插入的部分作为此插入结点父节点的右孩子,逆时针旋转一次,将此结点作为此子树的根结点,将其原父节点作为此 结点的左孩子,再将此结点的右孩子作为原树根结点的左孩子,顺时针旋转一次,将此结点作为整个树的根结点,将原根 结点作为新生成树的右孩子。 RL型:在A结点右子树根结点的左子树插入结点,导致A结点平衡因子由-1变-2 先顺时针旋转一次,后逆时针旋转一次; 将新插入的部分作为此插入结点父节点的左孩子,顺时针旋转一次,将此结点作为此子树的根结点,将其原父节点作为此 结点的右孩子,再将此结点的左孩子作为原树根结点的右孩子,逆时针旋转一次,将此结点作为整颗树的根结点,将原根 结点作为新生成树的左孩子。 高度为h的平衡二叉树结点的最小值问题:N1=1、N2=2、N3=4、N4=7 递推公式Nh=Nh-1+Nh-2+1;(前两项的值的和加1)
ltag
lchild
data
rchild
rtag
任何一颗和树对应的二叉树其根结点的右子树必定为空NULL。(左孩子,右兄弟)
(森林和二叉树可以相互转化)
森林转化成二叉树:
F={T1,T2,....}为一森林集合
如果F为NULL,则次此二叉树为空树;
如果F不为空,二叉树的根即为集合中T1的根,二叉树的左子树是T1根结点的子树森林中转化而成的二叉树,
二叉树的右子树为原集合中剩余部分所转化成的二叉树。
1、将所有树先转化成二叉树;
2、后一个二叉树作为前一个二叉树的右孩子,第一个二叉树为根。
树转化成二叉树:
1、连接具有相同双亲的兄弟结点
2、除了第一个孩子结点之外,删除剩余兄弟结点与双亲的连线。
3、剩余部分即为生成的二叉树。
1、加线:若某结点的左孩子结点存在,则将这个左孩子的右孩子结点、右孩子的右孩子结点、右孩子的右孩子的右孩子结点…,
都作为结点的孩子。将结点与这些右孩子结点用线连接起来。
2、去线:删除原二叉树中所有结点与其右孩子结点的连线。
3、层次调整。
B={root,LB,RB}
如果二叉树为空:则森林为空
如果二叉树不为空,则森林中第一颗树的根为二叉树的根root,T1中根结点的子树森林F1是由二叉树左子树LB转化
而成的森林;F中除了T1之外的其余树组成的森林F'={T2,T3,...}是由二叉树B的右子树转化而来的。
2、将生成的二叉树变成森林即可。
树
森林
二叉树
先根遍历
先序遍历
先序遍历
后根遍历
中序遍历
中序遍历