【数据结构十】平衡的二叉搜索树之 AVL 树、红黑树

比较好的树的数据应该是左右分布均匀的,称为平衡树。
如果插入连续数据,就会导致分布的不均匀,称为非平衡树。

因为二叉搜索树有它的缺陷,当它不平衡时会影响二叉搜索树查找、插入和删除的效率。为了不影响操作效率,需要保证二叉搜索树是平衡的,人们提出了很多解决方案,形成了很多新的树,这些新的树依然是二叉搜索树,只不过是在二叉搜索树的基础上,在插入和删除元素的时候能保持平衡性。

常见的平衡的二叉搜索树有:AVL 树和红黑树。

AVL 树:

AVL 树:是最先发明的平衡的二叉搜索树,简称平衡二叉树。一棵 AVL 树必须具备以下两个条件:它必须是二叉搜索树;每个节点的左子树和右子树的高度差至多为 1。

因为 AVL 树是平衡的,所以时间复杂度也是 O(logN)。但是,插入和删除操作相对于红黑树来说效率都不高,所以整体效率不如红黑树。因此,在实际开发中,使用较少。

红黑树:

红黑树除了符合二叉搜索树的基本规则外,还添加了以下规则:

  1. 节点必须是红色或黑色。

  2. 根节点只能是黑色。

  3. 任何包含数据的节点都不会作为叶子节点,每个叶子节点都是黑色的空节点(NIL 节点)。

  4. 每个红色节点的子节点都只能是黑色的,也就是说,从每个叶子节点到根节点的所有路径上都不能有两个连续的红色节点。

    黑色节点的子节点可以是黑色的,也可以是红色的

  5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

【数据结构十】平衡的二叉搜索树之 AVL 树、红黑树_第1张图片

红黑树的平衡性:

前面的规则,确保了红黑树的关键特性:相对平衡,从根节点到叶子节点的最长可能路径,不会超过最短可能路径的两倍长。那么这棵树基本就是平衡的。

为什么可以做到最长路径不超过最短路径的两倍呢?

  1. 规则 5 规定了所有路径都有相同数目的黑色节点,那么最短的可能路径就是都是黑色节点,最长的可能路径是红色和黑色交替。
  2. 规则 4 又规定了路径不能有两个相连的红色节点,那么假设最短路径是 4 个黑色节点,那么最长路径就是黑-红-黑-红-黑-红-黑 7个节点,这就表明没有路径能大于任何其他路径的两倍长。

红黑树的变换:

插入一个新节点后,可能会导致红黑树的不平衡。可以通过三种方式的变换,让红黑树保持平衡:变色、左旋转、右旋转。

变色:

变色:为了重新符合红黑树的规则,尝试把某个红色节点变为黑色,或者把黑色节点变为红色。

旋转:
  1. 左旋转:逆时针旋转红黑树的两个节点,使得父节点被自己的右子节点取代,而父节点取代原先的左子节点。
    原先的左子节点及其子树的连接不变;原先的右子节点的右子节点及其子树的连接不变;原先的右子节点的左子节点及其子树向左平移,转换为现在的左子节点的右子节点及其子树。

【数据结构十】平衡的二叉搜索树之 AVL 树、红黑树_第2张图片
2. 右旋转:顺时针旋转红黑树的两个节点,使得父节点被自己的左子节点取代,而父节点取代原先的右子节点。
原先的右子节点及其子树的连接不变;原先的左子节点的左子节点及其子树的连接不变;原先的左子节点的右子节点及其子树向右平移,转换为现在的右子节点的左子节点及其子树。
【数据结构十】平衡的二叉搜索树之 AVL 树、红黑树_第3张图片

红黑树的实现:

红黑树的插入和删除代码都非常复杂,作为前端知识的补充,了解原理即可。

插入操作:

在进行红黑树的插入操作时,插入的新节点通常都是红色节点。
因为如果插入黑色节点的话,必然会导致有一条路径上多了黑色节点,就不符合规则 5 了,那么其他所有路径都需要调整,非常麻烦,相比之下,插入红色节点就简单得多了。

假设要插入的节点为 N,且是红色的。如果它有父节点的话,父节点为 P;有祖先节点的话,祖先节点为 G;它的父节点有兄弟节点的话,为 U。有以下几种情况:

  1. 情况一:新节点 N 位于树的根上,此时没有父节点、祖父节点等。这种情况下,直接将红色变成黑色即可。

  2. 情况二:父节点 P 是黑色的,此时规则 4 和规则 5 都是满足的。这种情况下,直接插入新节点 N 即可。

  3. 情况三:父节点 P 是红色的,叔叔节点 U 也是红色的,祖先节点 G 是黑色的。此时出现了红红相连的情况,不符合规则 4。

    变换方法:将 P 和 U 变换为黑色,将 G 变换为红色。此时就符合规则 4 了;原来 G - P - N 和 G -U 这两条路径上都有一个黑色节点 G,现在只不过分别变成了黑色节点 P 和黑色节点 U,黑色节点的数目没有改变,还是符合规则 5 的。

    可能出现的问题: G 的父亲节点也有可能是红色的,这就不符合规则 4 了,此时就需要将 G 及其子树看作一个新插入的节点,递归地调整颜色。但是如果递归调整颜色到了根节点,就需要进行旋转了。

    变换口诀:父红叔红祖黑,需要变换成父黑叔黑祖红。
    【数据结构十】平衡的二叉搜索树之 AVL 树、红黑树_第4张图片

  4. 情况四:父节点 P 是红色的,叔叔节点 U 是黑色的,祖先节点 G 是黑色的,且新节点 N 是左子节点。

    变换方法:将 P 变换为黑色,G 变换为红色,然后以 G 为根进行右旋转。

    变换口诀:父红叔黑祖黑,且新节点是左子节点,首先需要变换成父黑祖红,叔不变,然后以祖先节点为根进行右旋转。 【数据结构十】平衡的二叉搜索树之 AVL 树、红黑树_第5张图片

  5. 情况五:父节点 P 是红色的,叔叔节点 U 是黑色的,祖先节点 G 是黑色的,且新节点 N 是右子节点。

    变换方法:首先以 P 为根进行左旋转;然后将 P 作为新插入的节点考虑即可。

    变换口诀:父红叔黑祖黑,且新节点是右子节点,首先需要以父节点为根进行左旋转,然后将父节点作为新插入的节点考虑即可。
    【数据结构十】平衡的二叉搜索树之 AVL 树、红黑树_第6张图片

假设:要依次插入 10、9、8、7、6、5,步骤如下:

  1. 插入 10:符合情况一。首先插入节点 10;然后将节点 10 的颜色改成黑色。
    【数据结构十】平衡的二叉搜索树之 AVL 树、红黑树_第7张图片

  2. 插入 9:符合情况二。将节点 9 插入到节点 10 的左侧,不需要任何变化。
    【数据结构十】平衡的二叉搜索树之 AVL 树、红黑树_第8张图片

  3. 插入 8:符合情况四。首先将节点 8 插入到节点 9 的左侧;然后将节点 9 变成黑色,节点 10 变成红色;然后以节点 10 为根进行右旋转。
    【数据结构十】平衡的二叉搜索树之 AVL 树、红黑树_第9张图片

  4. 插入 7:符合情况三。首先将节点 7 插入到节点 8 的左侧;然后将节点 8 变成黑色,节点 10 变成黑色,节点 9 变成红色;此时根节点 9 是红色不符合规则二,那么需要将这棵树整体当做一个新节点重新插入,将节点 9 变成黑色即可。
    【数据结构十】平衡的二叉搜索树之 AVL 树、红黑树_第10张图片

  5. 插入 6:符合情况四。首先将节点 6 插入到节点 7 的左侧;然后将节点 7 变成黑色,节点 8 变成红色;然后以节点 8 为根进行右旋转。
    【数据结构十】平衡的二叉搜索树之 AVL 树、红黑树_第11张图片

  6. 插入 5:符合情况三。首先将节点 5 插入到节点 6 的左侧;然后将节点 6 变成黑色,节点 8 变成黑色,节点 7 变成红色。
    【数据结构十】平衡的二叉搜索树之 AVL 树、红黑树_第12张图片

删除操作:

红黑树的删除操作,需要将二叉搜索树的删除操作和红黑树的插入规则结合起来考虑。

你可能感兴趣的:(数据结构与算法,数据结构与算法)