数据结构编程实践20讲(Python版)—08红黑树

时间:2024-10-10 10:16:26

本文目录

    • 08 红黑树(Red-Black Tree)
      • S1 说明
      • S2 示例
      • S3:红黑树代码
        • 问题1:数据库索引
        • 问题2:时间调度
        • 问题3:内存管理

往期链接

01 数组 02 链表 03 栈 04 队列 05 二叉树 06 二叉搜索树 07 AVL树

08 红黑树(Red-Black Tree)

S1 说明

红黑树是一种自平衡的二叉搜索树(BST),它具有以下特性,以保持树的平衡性,从而确保基本操作(如插入、删除和查找)的时间复杂度为 O(log n)。

红黑树的性质:

  • 每个节点是红色或黑色。
  • 根节点是黑色。
  • 每个叶子节点(Nil或空节点)是黑色。
  • 如果一个节点是红色,则它的两个子节点都是黑色(即没有两个红色节点相邻)。
  • 从任何节点到其每个叶子节点的所有路径都包含相同数量的黑色节点。

红黑树的应用

  • 数据库系统:用于实现索引,红黑树能够快速插入、删除和查找。
  • 内存管理:在一些内存分配器中,用于跟踪内存块的分配和释放。
  • 编程语言的标准库:如 C++ STL 中的 map 和 set,通常使用红黑树来实现。
  • 操作系统:在调度和资源管理中,红黑树可用于管理进程和任务。

红黑树和AVL树的对比

1. 平衡策略

  • AVL树:
    • 每个节点的平衡因子(左子树高度减去右子树高度)只能是 -1、0 或 1。
    • 更严格的平衡条件,通常导致树的高度更低。
  • 红黑树:
    • 通过颜色(红色或黑色)和一系列性质来保持平衡。
    • 允许更大的高度差,通常会导致树的高度相对较高。

2. 旋转操作

  • AVL树:
    • 在插入和删除操作后,可能需要进行多次旋转,以保持严格的平衡。
    • 单次操作后可能需要进行多次调整。
  • 红黑树:
    • 旋转和重新着色的操作相对较少,通常在插入或删除后最多只需进行两次旋转。

3. 查找性能

  • AVL树:
    • 由于更严格的平衡,查找操作通常更快,时间复杂度为 O(log n)。
  • 红黑树:
    • 查找操作的时间复杂度也是 O(log n),但由于可能的高度更高,查找速度可能稍慢于 AVL 树。

4. 插入和删除性能

  • AVL树:
    • 在插入和删除操作频繁的情况下,由于需要更多的旋转,性能可能较差。
  • 红黑树:
    • 对于插入和删除操作,红黑树的性能相对更好,更适合频繁修改的场景。

5. 应用场景

  • AVL树:
    • 适合查找频繁、插入和删除较少的场景。
    • 常用于需要快速查找的应用,例如内存管理和数据库索引。
  • 红黑树:
    • 更适合插入和删除操作频繁的场景。
    • 广泛用于各种标准库实现,例如 C++ STL 的 map 和 set。

S2 示例

import matplotlib.pyplot as plt
import networkx as nx
from networkx.drawing.nx_pydot import graphviz_layout

class Node:
    def __init__(self, data, color='R', left=None, right=None, parent=None):
        self.data = data
        self.color = color
        self.left = left
        self.right = right
        self.parent = parent

class RedBlackTree:
    def __init__(self):
        self.NIL = Node(data=None, color='B')  # 哨兵 NIL 节点,所有空子节点都指向它
        self.root = self.NIL  # 初始化根节点为 NIL

    def insert(self, key):
        node = Node(data=key, left=self.NIL, right=self.NIL)  # 创建新节点,初始为红色
        self._insert_node(node)
        self._fix_insert(node)

    def _insert_node(self, node):
        parent = None
        current = self.root

        # 找到插入位置
        while current != self.NIL:
            parent = current
            if node.data < current.data:
                current = current.left
            else:
                current = current.right

        node.parent = parent
        if parent is None:
            self.root = node  # 树为空,新节点作为根节点
        elif node.data < parent.data:
            parent.left = node
        else:
            parent.right = node

    def _fix_insert(self, node):
        # 修复红黑树性质
        while node != self.root and node.parent.color == 'R':
            parent = node.parent
            grandparent = node.parent.parent

            if parent == grandparent.left:
                uncle = grandparent.right
                if uncle.color == 'R':  # Case 1: 叔叔节点是红色
                    parent.color = 'B'
                    uncle.color = 'B'
                    grandparent.color = 'R'
                    node = grandparent