赞
踩
修改自:《Java高级程序员面试笔试宝典》(机械工业出版社)第5.3.3节
对于有序数列的查找,
二叉查找树即是以二分法思想设计的一种快速查找树,具有如下特性:
二叉查找树在进行多次插入和删除后,往往会朝着链表的方向退化,导致查找效率越来越低下。如图是极端情况下退化成链表的二叉查找树:
[图1 极端情况下的二叉查找树]
为了提高二叉树的查询效率,提出了平衡二叉树(AVL树)的概念,包括如下特点:
平衡二叉树是一棵空树或二叉查找树;
左右两个子树的高度差绝对值不超过1;
左右两个子树都是一棵平衡二叉树。
满足这些条件,查询时间复杂度不超过O(log_2n)。
在对平衡二叉树做插入或删除的时候,需要判断该树是否失衡,通过一系列旋转操作(自平衡),来让其始终满足平衡二叉树的条件,从而达到查找效率最优。
决定平该树是否失衡的关键变量为平衡因子bf,则:
bf§ = p左子树高度 - p右子树高度,
有如下特性:
下面以如下平衡二叉树为例,介绍不同操作后如何维持平衡二叉树的特性。
[图2 样例 - 平衡二叉树]
插入操作有四种失衡情况:
比如插入7,由于比10小,放在了10的左侧,此时受影响而失衡的最小子树如图:
[图3 插入结点7后的二叉树]
其左子树为根节点10,左侧插入了7,对于这种情况,可以以13为旋转点进行单向右旋,旋转后子树代替原树的13结点,重新构成了平衡二叉树,如图:
[图4 插入结点7右旋后的结果]
旋转方式和 2.2.1 的情况正好相反,参考 2.2.1 图解。
比如插入结点19后,找到失衡的最小子树如图:
[图5 插入结点19后的二叉树]
对该最小子树的左子树进行左旋,然后再对整棵树进行右旋,使子树重新恢复平衡:
[图6 插入19后先左再右旋转的结果]
旋转方式与 2.2.3 的情况相反,参考 2.2.3 的图例。
如果没有子结点,其实也满足该条件,即用空结点来替换当前结点。
[图7 删除结点31的情况]
如上图的情况,删除后符合LL单向右旋的情况。
如下例子删除结点76,首先交换76与72,然后删除原来72对应的结点。
可以看到最小失衡树根结点为31,平衡因子为2,其左子树10平衡因子为0,不满足之前LL旋转,也不满足LR旋转,和上一步一样,平衡因子0当作1一样的处理,进行LL单向右旋。
[图8 删除结点76]
红黑树也是一种自平衡二叉树,性能由于平衡二叉树,有如下五个性质:
推导过程:
性质5约束了黑色结点数目一定相等,性质4约束了不会有两个相邻的红色结点。所以可能的最长路径也就是以黑色结点结束的红黑相间的结点,红色结点数目最多为黑色结点数目-1,红色+黑色不可能超出黑色*2。
对红黑树进行增删操作,必定会违背这些性质,故也需要在插入删除时做一些特定的操作。
红黑树结点,除了和其他二叉树一样的 left / right / parent 结点引用之外,还有颜色(red/black)属性,以及是否为叶子结点(isNil)标记。
因为性质5的约束,所有新插入的结点都是红色结点。
假设插入结点为N,父结点为P,祖父结点为G,叔结点为U,定义一个函数 f(A, B),函数返回A结点相对于B结点的位置(left/right)。
插入流程:
(下图中空心结点表示红色结点,实心结点表示黑色结点)
[图9 U为红色的情况]
如下例,P在G左侧,N在P左侧,变色后作LL单向右旋转。
[图10 LL单向向右旋转]
如下例,P在G左侧,N在P右侧,以P为旋转点进行RR单向左旋。
[图11 RR单向左旋]
红黑树插入过程的主要操作有两种:
变色:用于调整两个红色结点相邻的情况,以适应性质4。
旋转:用于调整左右子树黑色结点数目不等的情况,以适应性质5。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。