二叉搜索树、红-黑树和平衡树

二叉搜索树

又名二叉查找树,英文缩写为BST

特点:

  1. 若它的左子树不空,则左子树上的所有节点的值均小于它的根结点的值;
  2. 若它的右子树不空,则右子树上的所有结点的值均大于它的根节点的值;
  3. 它的左、右子树也分别为二叉搜索树

如图所示为一个二叉搜索树:

优势:

  1. 有序性:若以“中序”遍历二叉树,则会产生一个所有结点关键字值的递增序列,如图所示的二叉搜索树,中序遍历的结果为:3、12、24、37、45、53、61、78、90、100;
  2. 高效性:插入和查找的高效性,其算法的时间复杂度为O(h),h表示树的高度,这是其它数据结构无法达到的。如:有序线性表虽然有序,但是插入算法的时间复杂度为O(n);堆的插入算法虽然时间复杂度为O(log2n),但是堆不具有有序性。

缺点:

不平衡性:二叉搜索树出现不平衡的情况,甚至出现极端情况——单链,如图,此时h=n,二叉搜索树就失去了它的效率优势,此时如果想要客服这种不平衡性,传统的优化方式为:平衡树红-黑树

在这里插入图片描述
算法:

  • 插入算法:
    • 从根节点出发,遇键值较大向左,遇键值较小向右,直到尾端,即为插入点
  • 删除算法:
    • 如果删除节点只有一个子节点,那么直接将子节点连接至父节点即可
      请添加图片描述

    • 如果删除节点有不止一个子节点,那么用右子树中的最小值取而代之即可。找到最小值很简单,一直向左走走到尽头即可
      请添加图片描述

平衡树

全称自平衡二叉搜索树,英文缩写为AVL

AVL tree是一个加上了额外平衡条件的二叉搜索树,其平衡条件的建立是为了确保整棵树的深度为O(logN),。

平衡条件:直观上最佳平衡条件是每个节点的左右子树有着同样的高度,但这未免太过苛刻,我们很难插入新元素而保持这样的平衡条件。AVL树退而求其次,要求任何节点的左右子树高度相差最多1,这是一种较弱的条件,但是也可以保证对数深度的平衡状态。

自平衡算法:
发生条件:当元素插入且插入成功之后

新元素的位置无非下面四种:

  1. 插入点位于X的左子节点的左子树 ---- 左左
  2. 插入点位于X的左子节点的右子树 ---- 左右
  3. 插入点位于X的右子节点的左子树 ---- 右左
  4. 插入点位于X的右子节点的右子树 ---- 右右

其中X表示平衡状态被破坏之各节点中最深的那一个,由于节点最多有两个子节点,而平衡被打破意味着X的左右节点的高度差为2
请添加图片描述

  • 情况1、4可以视为外侧插入,使用单旋转操作即可调整至平衡


如上图,左侧为旋转前,右侧为旋转后

为了调整平衡状态,我们希望将A提高一层,将C下降一层,也就是将看k1向上提高,k2向下下滑
根据二叉搜索树的特性,我们可以知道可k2>k1,所以k2必须成为新树形中k1的右子节点
根据二叉搜索树的特性,我们直到B子树处于k1与k2之间,那么新树形中的B子树必须落在K2的左侧。

  • 情况2、3可以视为内侧插入,使用双旋转操作即可调整至平衡
    请添加图片描述
    如上图,左侧为旋转前,右侧为旋转后

对于内测插入,单纯的进行一次单旋转是绝对不行的,因为旋转之后还是不平衡的,不妨可以自己画图试下。
对于内测插入的情况,唯一的可能就是将k2作为新的根节点,这使得(根据二叉搜索树的规则)k1必然成为k2的左子节点,k3必然成为k2的右子节点。

双旋转也并不是新鲜的算法,就是简单的进行两次单旋转即可。
双旋转具体流程:

  1. k2与k1进行一次单旋转,k1就可以作为k2的左子节点出现
  2. k2与k3进行一次单旋转,k3就可以作为k2的右子节点出现

请添加图片描述

红黑树

英文缩写为RB-tree

红黑树的规则:

  1. 每个节点不是红色就是黑色
  2. 根节点为黑色
  3. 如果节点为红,其子节点必须为黑
  4. 在任一节点至NULL(树尾端)的任意路径,黑节点数必须相同

根据规则我们可以分析出来以下几个执行的必然情况:

  1. 根据规则4,我们插入的元素必然是红色
  2. 元素找到插入点插入之后,如果插入节点的父节点为红,那么就不符合规则三,就必须做出改变
  3. 对于NULL元素,我们都视为黑色,这样我们就需要担心违反规则3.因为每一个路径到树尾端都会有一个尾端的NULL元素,所以对规则4黑色节点数相同不影响

如下图,向红黑树中插入3、8、35、75四个元素,因为新增节点必为红色,可以看出这四个元素不符合红黑树的规则,我们对这四个元素一一分析。

请添加图片描述
分析之前我们先明确一下各节点的命名:
X:新节点
P:新节点的父节点
G:新节点的父节点的父节点,即祖父节点
S:新节点的祖父节点除父节点外的另一个子节点,即伯父节点
GG:新节点的祖父节点的父节点,即曾祖父节点

  1. 状态1:S为黑且为外侧插入(对应插入的元素3)

    对P、G做一个单旋转,并更改P、G的颜色即可

请添加图片描述
2. 状态2:S为黑且为内侧插入(对应插入的元素8)

  • 对P、X做一次单旋转,并改变G、X的颜色
  • 对X、G做一次单旋转,无需更改颜色
    请添加图片描述
  1. 状态3:S为红且为外侧插入(对应插入的元素75)
  • 对P、G做一次单旋转,并改变X的颜色
  • 如果GG是黑色,一切搞定,如果GG是红色,那就有些麻烦,我们看状态4
    请添加图片描述
  1. 状态4:S为红且为外侧插入(对应插入的元素35)
  • 根据状态3进行相应的操作
  • 如果GG为红色,还需要继续根据情况继续往上进行操作,直到不出现父子同为红色为止
    请添加图片描述
    我们无需分析就可以想想得到,如果一直向上层结构发展,是非常消耗时效的,因此我们可以实施一个自上而下的程序。
    自上而下的程序逻辑:
    在新插入元素X时,会有一个从根节点向下搜寻插入点的过程,在这个过程中,如果发现某节点N的两个子节点为红色,那么就把X改为红色,并把两个子节点改为黑色。
    请添加图片描述

猜你喜欢

转载自blog.csdn.net/weixin_44081533/article/details/115016947