快速理解红黑树,从二叉排序树 → AVL树 → 红黑树的演变

二叉搜索树

  • 二叉搜索树又称为二叉排序树,英文为BST

一、定义

对于任何一个非叶子节点,要求左子节点的值比父节点小,右子节点的值比父节点大,并且任意一个节点的左右子树都是二叉搜索树,如下图所示:

image-20210411202247960

二、查找节点

查找某个节点,必须从根节点开始查找:

① 查找值比当前节点值大,则搜索右子树;

② 查找值等于当前节点值,停止搜索(终止条件);

③ 查找值小于当前节点值,则搜索左子树

三、插入节点

待插入的节点需要从根节点开始进行比较,小于根节点则与根节点左子树比较,反之则与右子树比较,直到左子树为空或右子树为空,则插入到相应为空的位置

四、遍历节点

① 中序遍历:左子树——》根节点——》右子树(最为常用)

② 前序遍历:根节点——》左子树——》右子树

③ 后序遍历:左子树——》右子树——》根节点

  • 快速得到中序遍历结果的方式:
    • 将整棵树按照垂直的方向投影至水平线,节点从左到右的顺序就是中序遍历的结果
image-20210411203029189

五、查找最大值和最小值

  • 最小值

    • 先找根的左节点,然后一直找这个左节点的左节点,直到找到没有左节点的节点,那么这个节点就是最小值
  • 最大值

    • 一直找根节点的右节点,直到没有右节点,就是最大值
image-20210411203144622

六、删除节点

6.1 该节点是叶子节点

要删除叶子节点,只需要改变该节点的父节点指向该节点的指针指向null即可

image-20210411203523668

6.2 该节点有一个子节点

删除有一个子节点的节点,只需要将其父节点原本指向该节点的指针,改为指向该节点的子节点即可

image-20210411203605515

6.3 该节点有两个子节点

  • 用被删除节点的中序遍历结果的后继节点来代替被删除的节点
    • 后继节点指的是比删除节点大的最小节点
image-20210411203856545

七、总结

  • 二叉查找树拥有二分查找的高性能又拥有链表一样的灵活性

  • 二叉查找树的缺陷

    image-20210411204232610

    解决缺陷的方式是使用AVL树

  • 二叉查找树的时间复杂度

    • 最优时间复杂度是O(logN)
    • 最坏时间复杂度是O(n)

AVL树

  • AVL树又称为平衡二叉树

一、定义

  • 一颗AVL树或者是空树,或者是具有下述特征的二叉排序树

    • 首先AVL树是一颗二叉排序树
    • 左子树与右子树的高度差的绝对值小于等于1
    • 左子树和右子树也是AVL树
  • 为了方便起见,给每个节点附加一个平衡因子

    • 平衡因子 = 节点左子树高度 - 节点右子树高度
    • AVL树的所有节点的平衡因子只能是 -1,0,1
image-20210411205435396

二、失衡的情况

当插入一个节点时可能会导致AVL树失衡,即出现平衡因子的绝对值大于1的节点,如图:

image-20210411210238257

如果AVL树失衡,则必须重新调整树的结构,使之恢复平衡

注意:当有多个节点同时失衡时,则认为失衡的节点是最小失衡子树的根节点,如下图:

image-20210411210510353

三、平衡调整的四种类型

调整的原则是:降低高度、保持二叉排序树的性质

image-20210411210633035
  • LL型

    • 右旋的规律:以某个节点作为旋转节点,其左子节点变为旋转节点的父节点,左子节点的右子节点变为旋转节点的左子节点,旋转节点的右子树保持不变,如下图所示:

      image-20210412124144646

  • RR型

    • 左旋的规律:以某个节点作为旋转节点,其右子节点变为旋转节点的父节点,右子节点的左子节点变为旋转节点的右子节点,旋转节点的左子树保持不变,如下图所示:

      image-20210412124126683

  • LR型

    • 对照上述彩色图,首先以B作为旋转节点进行左旋,此时A→C→B成为LL型,再将A作为旋转节点进行右旋
  • RL型

    • 对照上述彩色图,首先以B作为旋转节点进行右旋,此时A→C→B成为RR型,再将A作为旋转节点进行左旋
  • 综上所述

    • 对于LR型、RL型都需要先以中间节点为旋转节点将结构转换成LL型或RR型,再以第一个节点为旋转节点进行左旋或右旋

四、平衡调整示例

关键字序列为(16,3,7,11,9,26,18,14,15),给出构造AVL树的过程

image-20210411212730797 image-20210411212940994 image-20210411212956564 image-20210411213019676 image-20210411213033845 image-20210411213100124

AVL树缺陷:

每次进行插入/删除节点的时候,几乎都会破坏平衡树的规则,进而需要通过左旋和右旋来进行调整,使之再次成为一颗符合要求的平衡树,在插入、删除很频繁的场景中,平衡树需要频繁的进行调整,这会使平衡树的性能大打折扣,解决缺陷的方式是使用红黑树

五、时间复杂度

平均和最坏情况下都是O(logN)

红黑树

一、红黑树的性质

  • 性质1:每个节点要么是黑色,要么是红色
  • 性质2:根节点是黑色
  • 性质3:每个叶子节点(NIL)都是黑色(取值为null的黑色叶子节点)
  • 性质4:每个红色节点的两个子节点一定都是黑色(两个红色节点不能成为父子关系)
  • 性质5:任意一节点到每个黑色叶子节点的路径都包含数量相同的黑色节点,俗称黑高

以上是红黑树的五条原则

根据以上原则,可以推断出如下:

  • 红黑树必须满足二叉搜索树的性质
  • 如果一个节点存在黑子节点,那么该结点肯定有两个子节点
    • 目的是为了满足黑高的特性
    • 另一个子节点可红可黑,如果为红,其后面还可以添加黑色节点来满足黑高的特性
    • 如果该节点是红色节点,则另一个子节点一定是黑色节点

红黑树示意图:

image-20210412123304445

从上图可以得到:

  • 黑色节点的孩子节点可红可黑

  • 红黑树并不是一个完美的AVL树,从图上可以看到,根结点P的左子树显然比右子树高

  • 红黑树的平衡称为黑色完美平衡

    • 任意一个结点到每个黑色叶子结点的路径都包含数量相同的黑色结点

二、红黑树的自平衡

  • 红黑树可以保持自平衡,通过三种操作实现

    • 变色:结点的颜色由红变黑或由黑变红

    • 左旋:以某个结点作为支点(旋转结点),其右子结点变为旋转结点的父结点,右子结点的左子结点变为旋转结点的右子结点,旋转节点的左子结点保持不变

      image-20210412124126683
    • 右旋:以某个结点作为支点(旋转结点),其左子结点变为旋转结点的父结点,左子结点的右子结点变为旋转结点的左子结点,旋转节点的右子结点保持不变

      image-20210412124144646

三、红黑树的插入

注意:红黑树插入的默认是红色节点,因为如果插入黑色节点,就会破坏黑高的特性,插入位置所在的子树黑色结点总是多1,必须做自平衡操作,并且调整起来更加复杂,如下图所示:

image-20210412125454804

插入节点之前,先按下图所示做一个约定:

image-20210412125642629

1. 红黑树为空树

最简单的一种情景,直接把插入结点作为根结点即可

注意:根据红黑树性质,根节点是黑色,故还需要把红色的插入结点设为黑色

2. 插入节点的key已存在

更新当前节点的值为插入节点的值,如图所示:

image-20210412125954298

3. 插入节点的父节点是黑色节点

由于插入的结点是红色的,当插入结点的父节点是黑色时,并不会影响红黑树的平衡,直接插入即可,无需做自平衡操作,如图所示:

image-20210412130145966

4. 插入节点的父节点是红色节点

红黑树有一个特性,根节点是黑色节点,如果插入节点的父节点为红色节点,那么该父节点不可能是根节点,也就是说插入结点总是存在祖父结点(祖父节点不一定是根节点),分以下两种情况讨论:

image-20210412132457938
4.1 叔叔节点存在且为红色节点
  • 根据红黑树的性质,两个红色节点不能成为父子关系,由于父节点是红色节点,故祖父节点一定是黑色节点

  • 插入此节点后,层级关系是:黑红红,不满足两个红色节点不能成为父子关系的条件,故需要进行调整

    • 可以将层级关系修改为红黑红(因为要满足黑高的特性,故不可修改为黑黑红),过程如下:

      • 将P和U节点改为黑色
      • 将PP改为红色
      image-20210412134547983

      从上图可以看到,把PP结点(祖父节点)设为红色了,如果PP的父结点是黑色,那么无需再做任何处理;但如果PP的父结点是红色,则违反红黑树的性质了,所以需要将PP设置为当前节点,继续做自平衡处理,直到平衡为止(此时虽然是LL型,但保持了平衡,故无需旋转)

4.2 叔叔结点不存在,且插入结点的父结点是祖父结点的左子结点
image-20210412135035374
4.2.1 插入节点是父节点的左子节点(LL型)
  • 处理过程
    • 将P设置为黑色,将PP设置为红色
    • 对PP节点进行右旋
image-20210412135424447
4.2.2 插入节点是父节点的右子节点(LR型)
  • 处理过程
    • 对P进行左旋,得到LL型结构(成为LL或RR型结构才可以变色)
    • 按照LL型结构进行处理(变色 + 右旋)
image-20210412140656862
4.3 叔叔结点不存在,且插入结点的父结点是祖父结点的右子结点
image-20210412141213627
4.3.1 插入节点是父节点的右子节点(RR型)
  • 处理过程
    • 将P设置为黑色,将PP设置为红色
    • 对PP节点进行左旋
image-20210412141327158
4.3.2 插入节点是父节点的左子节点(RL型)
  • 处理过程
    • 对P进行右旋,得到RR型结构(成为LL或RR型结构才可以变色)
    • 按照RR型结构进行处理(变色 + 左旋)
image-20210412141723184

四、插入节点的综合案例

image-20210412143908212

五、红黑树的搜索

红黑树本来就是平衡二叉树,并且搜索也不会破坏树的平衡,所以搜索算法也与AVL树一致

image-20210412142422842

六、时间复杂度

红黑树各种操作的时间复杂度都为O(logN)

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Nice2cu_Code

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值