《算法4》 查找树

Posted by boredream on August 10, 2018

不同数据结构

  • 无序链表 直接遍历循环一遍,O(n)
  • 有序数组 二分查找法,O(lgn)。
    但插入效率不高,二分查找插入后,后面数据要全后移一位,O(lgn) + O(n) = O(n)
  • 查找二叉树 将数据结构直接做成二分+链式的。规则 左结点 < 根结点 < 右结点
    这样查找、插入都是对数级别 O(lgn)。二分查完后直接末尾插入。

但查找二叉树在最坏的情况下,等同于一个有序链式数组,查找效率又变回了O(n) tree1 所以我们引入平衡二叉树概念,让二叉树更满~

  • 平衡查找树(2-3结点查找树) 平衡的概念是,保证左右子树的高度差不能大于1,让树铺更满,达到任何情况下都是 lgn。
    原有1对2叫2-结点,规则不变。
    新增一种2对3结点,称为3-结点。
    规则 左结点 < 根结点-左 < 中结点 < 根结点-右 < 右结点

时间复杂度一览

tree2

平衡查找树

tree3 新规则依然可以类似的二分查找,从上到下依次判断。
每个结点跟俩元素根据大小,判断应该走哪个分支。

但插入会复杂一点,不同于普通查找树插入到末尾结点的下面空位置。
而是直接塞到末尾结点上,则插入后: 2-结点变成3-结点。
3-结点变成4-结点。这个就要升级一下了,将中间的元素挤上去变成一个两层的2-结点树 tree4 在整个树结构里,就会将元素挤到根结点里,然后根结点等于也插入了一个元素,规则一样。
整个流程类似于三进制系统,末尾+1后向前依次判断是否进一位。

所以不同于普通查找树从上到下末尾不停插。
平衡二叉树是从下到上不停的挤上去,这样就保证了平衡。

红黑树(平衡查找树的一种实现)

2-3查找树是改造结点+分支,红黑树思想是只改分支链接线。
红链接:将两个2-结点连起来,等同于一个3-结点。 黑链接:和之前的普通连接一样。

被某个颜色链接指向的结点,也叫做红/黑结点。根结点是黑。

注意:

  • 红链接均为左链接
  • 没有结点同时包含俩红链接
  • 该树是 完美黑色平衡的。即任意空链接到根结点的路径上黑链接数量相同。

红链接如果横着画,就更好理解了,直接看上去就和2-3结点树差不多,比较满~平衡~ tree5

等价于一个2-3结点,所以lgn有保证,且又不破坏传统二叉树的1对2结构。 那么如何构建呢? 2-3树永远都是在末尾的结点直接插入一个新元素。 同理红黑树则永远在末尾插入一个红链接元素,相当于在这个节点内插入。 然后在插入后要考虑是否挤上去的问题,除此之外红黑树还需要保证红链接在左的特性。 这里就要用到 旋转 去保证操作后的红黑规则。

主要分为左转和右旋 tree6 左旋是为了把红链接从右边旋转到左边,保证规则。 右旋转则是把红链接从左转到右边,为什么逆着规则呢? 如果连续俩左红链接不平衡了,所以要右旋转,调整成一个完整的1对2结点

实际流程如下: 对于2-结点插入新元素 tree7

对于3-结点插入新元素 tree8

2-结点很简单,插入后右红左旋转成左红 3-结点比较复杂,不同情况,最终希望转成一个左右红,然后进一位(左右红变黑,指向根结点的链接变红) 总的依然是从下到上,依次判断左旋先都保证红链接在左。然后如果仨是连续俩左链式失衡,则根结点右旋转变成一个平衡的左右红,然后再颜色变化进一位升级。 tree9

其实和2-3结点很类似,颜色变化就类似于4-结点往上挤一位 只不过多了旋转用来保证红链接在左,以及进一位之前的位置调整 tree10

综上

  • 右红+左黑,左旋转调整成左红右黑
  • 左红+左子左红,右旋转成双红,然后颜色变换

应用

Java中有封装基于红黑树的实现 java.util.TreeMap

问题

Q:为什么红链接不能在右? A:其实都都行,方便计算代码实现