📜  红黑树与 AVL 树(1)

📅  最后修改于: 2023-12-03 15:11:37.167000             🧑  作者: Mango

红黑树与 AVL 树

简介

红黑树和AVL树都是常用的自平衡二叉搜索树,它们在插入和删除结点时,都能对树进行自我平衡,从而保持树的高度较小,查询效率较高。

AVL树

AVL树是以其发明者 Adelson-Velsky 和 Landis(AVL)的名字命名的,是一种高度平衡的二叉搜索树。在AVL树中,任何节点的两个儿子子树的高度最大差别为1,也就是说AVL树的高度是0(log n)。因此,可以确保它的查找,插入和删除在平均和最坏情况下的时间复杂度为O(log n)。

AVL树的平衡是通过旋转操作来保持的,包括 左旋 和 右旋 操作,当发现不平衡时进行旋转,旋转结束后,AVL树就恢复了平衡。

红黑树

相对于AVL树而言,红黑树的平衡性不如AVL树那么严格,但是它的平衡性能更好,对于搜索,插入,删除操作,它的时间复杂度都能够保证在 O(log n)。

在红黑树中,每个节点都被标记为红色或黑色,根节点始终是黑色的。红黑树具有以下五个性质:

  1. 每个节点是红色或黑色的。
  2. 根节点是黑色的。
  3. 如果一个节点是红色的,则它的子节点必须是黑色的(反之不一定)。
  4. 如果一个节点是黑色的,则它的每个子节点必须是黑色的,且最多只有一个子节点为红色。
  5. 从任意一个节点到它的每个叶子节点的所有路径都包含相同数目的黑色节点。

红黑树的平衡是通过颜色变换和旋转操作来实现的,其中颜色变换包括 将红节点变为黑节点,将黑节点变为红节点。

比较

AVL 树和红黑树都是自平衡二叉搜索树,但是它们之间在平衡性的要求、实现方式和性能等方面还是有所区别的。

  • 平衡性的要求:AVL 树的平衡性要求比红黑树更为严格,对插入、删除等操作的局限性也更大;红黑树对于平衡的要求相对更松懈,能够适应更广泛的场景。

  • 实现方式:AVL 树通过平衡因子来实现平衡,需要在插入、删除等操作中同时考虑平衡因子和旋转;红黑树则通过节点颜色的变化和旋转来实现平衡,更为简单,插入、删除等操作也更为灵活、高效。

  • 性能:AVL 树的平衡要求更高,因此查询效率略高于红黑树,但是随着数据的动态变化,AVL 树的旋转次数也会增多,导致效率下降;红黑树的查询效率比 AVL 树略低,但是由于平衡性的要求不如 AVL 树高,因此对于动态数据变化的适应性更强,一般情况下更易于维护和优化。

总结

AVL 树和红黑树都是二叉搜索树的变种,它们的自平衡能力保证了它们能够高效地支持插入、查询和删除等操作。AVL 树的平衡性要求更为严格,但同时局限性也更大;红黑树的平衡性要求相对较低,因此适应性更强。两种树的时间复杂度较为均衡,选择哪一种取决于具体场景的需求和数据特点。

参考资料:

  1. https://zh.wikipedia.org/wiki/AVL%E6%A0%91
  2. https://zh.wikipedia.org/wiki/%E7%BA%A2%E9%BB%91%E6%A0%91
  3. https://www.jianshu.com/p/9c94f2d8dcfe
# Python 实现 AVL 树和红黑树

# AVL 树的代码
class Node:
    def __init__(self, value):
        self.value = value
        self.left = None
        self.right = None
        self.height = 1

class AVL_Tree:
    
    def insert(self, root, key):
        
        if not root:
            return Node(key)
        elif key < root.value:
            root.left = self.insert(root.left, key)
        else:
            root.right = self.insert(root.right, key)
 
        root.height = 1 + max(self.get_height(root.left), self.get_height(root.right))
 
        balance = self.get_balance(root)
 
        if balance > 1 and key < root.left.value:
            return self.right_rotate(root)
 
        if balance < -1 and key > root.right.value:
            return self.left_rotate(root)
 
        if balance > 1 and key > root.left.value:
            root.left = self.left_rotate(root.left)
            return self.right_rotate(root)
 
        if balance < -1 and key < root.right.value:
            root.right = self.right_rotate(root.right)
            return self.left_rotate(root)
 
        return root
    
    def left_rotate(self, z):
 
        y = z.right
        T2 = y.left
 
        y.left = z
        z.right = T2
 
        z.height = 1 + max(self.get_height(z.left),
                           self.get_height(z.right))
        y.height = 1 + max(self.get_height(y.left),
                           self.get_height(y.right))
 
        return y
 
    def right_rotate(self, z):
 
        y = z.left
        T3 = y.right
 
        y.right = z
        z.left = T3
 
        z.height = 1 + max(self.get_height(z.left),
                           self.get_height(z.right))
        y.height = 1 + max(self.get_height(y.left),
                           self.get_height(y.right))
 
        return y
    
    def get_height(self, root):
        if not root:
            return 0
        return root.height
 
    def get_balance(self, root):
        if not root:
            return 0
        return self.get_height(root.left) - self.get_height(root.right)

# 红黑树的代码
class Node:
    def __init__(self, val):
        self.val = val
        self.left = None
        self.right = None
        self.parent = None
        self.color = 1
 
class RedBlackTree:
    def __init__(self):
        self.nullNode = Node(0)
        self.nullNode.color = 0
        self.nullNode.left = None
        self.nullNode.right = None
        self.root = self.nullNode

    def insert(self, key):
        node = Node(key)
        node.parent = None
        node.val = key
        node.left = self.nullNode
        node.right = self.nullNode
        node.color = 1

        y = None
        x = self.root

        while x != self.nullNode:
            y = x
            if node.val < x.val:
                x = x.left
            else:
                x = x.right

        node.parent = y
        if y == None:
            self.root = node
        elif node.val < y.val:
            y.left = node
        else:
            y.right = node

        if node.parent == None:
            node.color = 0
            return

        if node.parent.parent == None:
            return

        self.fix_insert(node)

    def fix_insert(self, k):
        while k.parent.color == 1:
            if k.parent == k.parent.parent.right:
                u = k.parent.parent.left 
                if u.color == 1:
                    u.color = 0
                    k.parent.color = 0
                    k.parent.parent.color = 1
                    k = k.parent.parent
                else:
                    if k == k.parent.left:
                        k = k.parent
                        self.right_rotate(k)
                    k.parent.color = 0
                    k.parent.parent.color = 1
                    self.left_rotate(k.parent.parent)
            else:
                u = k.parent.parent.right
 
                if u.color == 1:
                    u.color = 0
                    k.parent.color = 0
                    k.parent.parent.color = 1
                    k = k.parent.parent 
                else:
                    if k == k.parent.right:
                        k = k.parent
                        self.left_rotate(k)
                    k.parent.color = 0
                    k.parent.parent.color = 1
                    self.right_rotate(k.parent.parent)
            if k == self.root:
                break
        self.root.color = 0

    def left_rotate(self, x):
        y = x.right
        x.right = y.left
        if y.left != self.nullNode:
            y.left.parent = x
 
        y.parent = x.parent
        if x.parent == None:
            self.root = y
        elif x == x.parent.left:
            x.parent.left = y
        else:
            x.parent.right = y
        y.left = x
        x.parent = y

    def right_rotate(self, x):
        y = x.left
        x.left = y.right
        if y.right != self.nullNode:
            y.right.parent = x
 
        y.parent = x.parent
        if x.parent == None:
            self.root = y
        elif x == x.parent.right:
            x.parent.right = y
        else:
            x.parent.left = y
        y.right = x
        x.parent = y