Skip to content

第14章 平衡树理论

本章导读

平衡树是保证操作复杂度为 $O(\log n)$ 的自平衡二叉搜索树。本章从形式化角度深入分析平衡树的数学基础,包括AVL树的高度平衡性质与旋转正确性证明、红黑树的红黑性质与高度上界证明,以及两种平衡树的性能对比分析。

学习目标

完成本章学习后,读者将能够:

  • 掌握平衡树的数学定义与平衡条件
  • 理解AVL树旋转操作的正确性证明
  • 掌握红黑树高度上界的数学推导
  • 理解红黑树插入修复的正确性
  • 掌握平衡树的选择标准与应用场景

14.1 平衡树的形式化定义

14.1.1 平衡性的数学定义

定义 14.1(平衡因子) 节点 $v$ 的平衡因子定义为:

$$BF(v) = h(left(v)) - h(right(v))$$

其中 $h(v)$ 表示节点 $v$ 的高度。

定义 14.2(高度平衡) 二叉树 $T$ 是高度平衡的,当且仅当:

$$\forall v \in T: |BF(v)| \leq 1$$

定义 14.3(平衡二叉搜索树) 平衡二叉搜索树是同时满足BST性质和平衡性质的二叉搜索树。

定理 14.1(平衡树高度上界) $n$ 个节点的平衡二叉搜索树的高度 $h$ 满足:

$$h = O(\log n)$$

证明:设 $N_h$ 为高度为 $h$ 的平衡二叉搜索树的最少节点数。

高度为 $h$ 的平衡树由根节点和两棵子树组成,其中一棵高度为 $h-1$,另一棵高度至少为 $h-2$(由平衡条件)。

因此:

$$N_h = 1 + N_{h-1} + N_{h-2}$$

这与斐波那契数列的递推关系相同。解得:

$$N_h \geq \phi^h$$

其中 $\phi = \frac{1+\sqrt{5}}{2}$ 是黄金比例。

因此 $h \leq \log_\phi n = O(\log n)$。∎

14.1.2 平衡树ADT

ADT 14.1(BalancedBST)

ADT BalancedBST[K: Ordered]
  Types: BalancedBST[K]
  
  Operations:
    所有BST操作
    rebalance: BalancedBST[K] → BalancedBST[K]
  
  Axioms:
    所有BST公理
    (A1) rebalance后树满足平衡条件
    (A2) rebalance后中序遍历不变

14.2 AVL树理论

14.2.1 AVL树的数学定义

定义 14.4(AVL树) AVL树是满足以下性质的二叉搜索树:

$$\forall v \in T: |BF(v)| \leq 1$$

定理 14.2(AVL树高度上界) $n$ 个节点的AVL树的高度 $h$ 满足:

$$h < 1.44 \log_2(n+2) - 0.328$$

证明:设 $N_h$ 为高度为 $h$ 的AVL树的最少节点数。

$$N_h = N_{h-1} + N_{h-2} + 1$$

边界条件:$N_0 = 1$,$N_1 = 2$。

解此递推关系,设 $N_h = \alpha \phi^h + \beta \hat{\phi}^h - 1$,其中 $\phi = \frac{1+\sqrt{5}}{2}$,$\hat{\phi} = \frac{1-\sqrt{5}}{2}$。

由于 $|\hat{\phi}| < 1$,当 $h$ 足够大时:

$$N_h \approx \alpha \phi^h$$

因此 $h \approx \log_\phi N_h = \frac{\ln N_h}{\ln \phi} \approx 1.44 \log_2 n$。∎

14.2.2 旋转操作的正确性

定义 14.5(右旋) 对节点 $y$ 进行右旋:

    y                x
   / \              / \
  x   T3    →     T1   y
 / \                  / \
T1  T2              T2  T3

定理 14.3(旋转保持BST性质) 旋转操作保持BST性质。

证明:右旋前,$x < y$,$T1 < x < T2 < y < T3$。

右旋后:

  • $T1$ 在 $x$ 的左子树,满足 $T1 < x$
  • $T2$ 在 $y$ 的左子树,满足 $T2 < y$
  • $T3$ 在 $y$ 的右子树,满足 $y < T3$
  • $x < y$($x$ 是 $y$ 的父节点)

因此BST性质保持。左旋类似。∎

定理 14.4(旋转保持中序遍历) 旋转操作不改变树的中序遍历序列。

证明:右旋前的中序遍历:$inorder(T1) \cdot x \cdot inorder(T2) \cdot y \cdot inorder(T3)$

右旋后的中序遍历:$inorder(T1) \cdot x \cdot inorder(T2) \cdot y \cdot inorder(T3)$

两者相同。∎

14.2.3 AVL树插入修复

定理 14.5(AVL插入修复正确性) 插入后通过最多一次双旋或两次单旋可恢复平衡。

证明:设插入后第一个失衡节点为 $z$,其较高子节点为 $y$,$y$ 的较高子节点为 $x$。

分四种情况:

  1. LL型($y$ 是 $z$ 的左子,$x$ 是 $y$ 的左子):对 $z$ 右旋
  2. RR型($y$ 是 $z$ 的右子,$x$ 是 $y$ 的右子):对 $z$ 左旋
  3. LR型($y$ 是 $z$ 的左子,$x$ 是 $y$ 的右子):先对 $y$ 左旋,再对 $z$ 右旋
  4. RL型($y$ 是 $z$ 的右子,$x$ 是 $y$ 的左子):先对 $y$ 右旋,再对 $z$ 左旋

每种情况修复后,子树高度恢复到插入前,因此无需继续向上修复。∎

14.2.4 AVL树实现

python
from typing import TypeVar, Generic, Optional, List, Iterator

T = TypeVar('T')

class AVLNode(Generic[T]):
    """AVL树节点"""
    __slots__ = ['key', 'left', 'right', 'height']
    
    def __init__(self, key: T):
        self.key = key
        self.left: Optional['AVLNode[T]'] = None
        self.right: Optional['AVLNode[T]'] = None
        self.height: int = 1


class AVLTree(Generic[T]):
    """
    AVL树实现
    
    时间复杂度:
    - 查找:O(log n)
    - 插入:O(log n)
    - 删除:O(log n)
    
    空间复杂度:O(n)
    
    特点:
    - 严格平衡:高度差 ≤ 1
    - 查找效率最高
    - 插入删除可能需要多次旋转
    """
    
    def _height(self, node: Optional[AVLNode[T]]) -> int:
        return node.height if node else 0
    
    def _balance_factor(self, node: Optional[AVLNode[T]]) -> int:
        if not node:
            return 0
        return self._height(node.left) - self._height(node.right)
    
    def _update_height(self, node: AVLNode[T]) -> None:
        node.height = 1 + max(self._height(node.left), self._height(node.right))
    
    def _rotate_right(self, y: AVLNode[T]) -> AVLNode[T]:
        """右旋"""
        x = y.left
        T2 = x.right
        
        x.right = y
        y.left = T2
        
        self._update_height(y)
        self._update_height(x)
        
        return x
    
    def _rotate_left(self, x: AVLNode[T]) -> AVLNode[T]:
        """左旋"""
        y = x.right
        T2 = y.left
        
        y.left = x
        x.right = T2
        
        self._update_height(x)
        self._update_height(y)
        
        return y
    
    def _rebalance(self, node: AVLNode[T]) -> AVLNode[T]:
        """重新平衡"""
        self._update_height(node)
        balance = self._balance_factor(node)
        
        if balance > 1:
            if self._balance_factor(node.left) < 0:
                node.left = self._rotate_left(node.left)
            return self._rotate_right(node)
        
        if balance < -1:
            if self._balance_factor(node.right) > 0:
                node.right = self._rotate_right(node.right)
            return self._rotate_left(node)
        
        return node
    
    def insert(self, root: Optional[AVLNode[T]], key: T) -> AVLNode[T]:
        """插入 - O(log n)"""
        if not root:
            return AVLNode(key)
        
        if key < root.key:
            root.left = self.insert(root.left, key)
        elif key > root.key:
            root.right = self.insert(root.right, key)
        else:
            return root
        
        return self._rebalance(root)
    
    def delete(self, root: Optional[AVLNode[T]], key: T) -> Optional[AVLNode[T]]:
        """删除 - O(log n)"""
        if not root:
            return None
        
        if key < root.key:
            root.left = self.delete(root.left, key)
        elif key > root.key:
            root.right = self.delete(root.right, key)
        else:
            if not root.left:
                return root.right
            if not root.right:
                return root.left
            
            successor = self._min_node(root.right)
            root.key = successor.key
            root.right = self.delete(root.right, successor.key)
        
        return self._rebalance(root)
    
    def search(self, root: Optional[AVLNode[T]], key: T) -> Optional[AVLNode[T]]:
        """查找 - O(log n)"""
        if not root:
            return None
        if key == root.key:
            return root
        if key < root.key:
            return self.search(root.left, key)
        return self.search(root.right, key)
    
    def _min_node(self, node: Optional[AVLNode[T]]) -> Optional[AVLNode[T]]:
        while node and node.left:
            node = node.left
        return node
    
    def inorder(self, root: Optional[AVLNode[T]]) -> List[T]:
        """中序遍历"""
        result = []
        def _traverse(node: Optional[AVLNode[T]]):
            if node:
                _traverse(node.left)
                result.append(node.key)
                _traverse(node.right)
        _traverse(root)
        return result
    
    def is_balanced(self, root: Optional[AVLNode[T]]) -> bool:
        """验证平衡性"""
        if not root:
            return True
        
        if abs(self._balance_factor(root)) > 1:
            return False
        
        return self.is_balanced(root.left) and self.is_balanced(root.right)


def demonstrate_avl():
    """演示AVL树"""
    tree = AVLTree[int]()
    root = None
    
    keys = [10, 20, 30, 40, 50, 25]
    for key in keys:
        root = tree.insert(root, key)
        print(f"插入 {key} 后: {tree.inorder(root)}")
    
    print(f"\n平衡验证: {tree.is_balanced(root)}")
    print(f"树高度: {tree._height(root)}")


if __name__ == '__main__':
    demonstrate_avl()

14.3 红黑树理论

14.3.1 红黑树的数学定义

定义 14.6(红黑树) 红黑树是满足以下五条性质的二叉搜索树:

  1. 颜色性质:每个节点是红色或黑色
  2. 根性质:根节点是黑色
  3. 叶子性质:所有叶子(NIL)节点是黑色
  4. 红色性质:红色节点的两个子节点都是黑色
  5. 黑高性质:从任一节点到其每个叶子的所有路径包含相同数量的黑色节点

定义 14.7(黑高) 节点 $v$ 的黑高 $bh(v)$ 定义为从 $v$ 到叶子(不含 $v$)的路径上黑色节点的数量。

定理 14.6(红黑树高度上界) $n$ 个节点的红黑树的高度 $h$ 满足:

$$h \leq 2\log_2(n+1)$$

证明:首先证明以节点 $x$ 为根的子树至少包含 $2^{bh(x)} - 1$ 个内部节点。

归纳基础:若 $x$ 是叶子,子树包含 $0 = 2^0 - 1$ 个节点。

归纳步骤:设 $x$ 有两个子节点,每个子节点的黑高至少为 $bh(x) - 1$(若子节点是红色)或 $bh(x)$(若子节点是黑色)。因此每个子树至少有 $2^{bh(x)-1} - 1$ 个节点。

总节点数:$n \geq 2(2^{bh(x)-1} - 1) + 1 = 2^{bh(x)} - 1$。

由红色性质,从根到叶子的路径上至少一半节点是黑色(根是黑色,红色节点后必须是黑色)。

因此 $bh(root) \geq h/2$。

代入:$n \geq 2^{h/2} - 1$,即 $h \leq 2\log_2(n+1)$。∎

14.3.2 红黑树插入修复

定理 14.7(红黑树插入修复正确性) 插入后通过最多两次旋转可恢复红黑性质。

证明:设新插入的节点为 $z$,初始着为红色。可能违反红色性质。

分三种情况(设 $z$ 的父节点是祖父节点的左子):

情况1:叔节点是红色

  • 将父节点和叔节点着为黑色,祖父节点着为红色
  • 将 $z$ 上移到祖父节点
  • 可能继续向上修复

情况2:叔节点是黑色,$z$ 是右子

  • 对父节点左旋
  • 转化为情况3

情况3:叔节点是黑色,$z$ 是左子

  • 将父节点着为黑色,祖父节点着为红色
  • 对祖父节点右旋
  • 修复完成

情况2和3最多需要一次旋转,情况1可能向上传播但最多 $O(\log n)$ 次。∎

14.3.3 红黑树实现

python
from typing import TypeVar, Generic, Optional, List
from enum import Enum

T = TypeVar('T')

class Color(Enum):
    RED = True
    BLACK = False


class RBNode(Generic[T]):
    """红黑树节点"""
    __slots__ = ['key', 'left', 'right', 'parent', 'color']
    
    def __init__(self, key: T, color: Color = Color.RED):
        self.key = key
        self.left: Optional['RBNode[T]'] = None
        self.right: Optional['RBNode[T]'] = None
        self.parent: Optional['RBNode[T]'] = None
        self.color = color
    
    def is_red(self) -> bool:
        return self.color == Color.RED
    
    def is_black(self) -> bool:
        return self.color == Color.BLACK


class RedBlackTree(Generic[T]):
    """
    红黑树实现
    
    时间复杂度:
    - 查找:O(log n)
    - 插入:O(log n)
    - 删除:O(log n)
    
    空间复杂度:O(n)
    
    特点:
    - 近似平衡:h ≤ 2log(n+1)
    - 插入删除旋转次数少(最多2次)
    - 工程应用广泛
    """
    
    NIL = RBNode(None, Color.BLACK)
    
    def __init__(self):
        self._root: Optional[RBNode[T]] = None
        self._size: int = 0
    
    def _left_rotate(self, x: RBNode[T]) -> None:
        """左旋"""
        y = x.right
        x.right = y.left
        
        if y.left:
            y.left.parent = x
        
        y.parent = x.parent
        
        if not x.parent:
            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, y: RBNode[T]) -> None:
        """右旋"""
        x = y.left
        y.left = x.right
        
        if x.right:
            x.right.parent = y
        
        x.parent = y.parent
        
        if not y.parent:
            self._root = x
        elif y == y.parent.left:
            y.parent.left = x
        else:
            y.parent.right = x
        
        x.right = y
        y.parent = x
    
    def _insert_fixup(self, z: RBNode[T]) -> None:
        """插入修复"""
        while z.parent and z.parent.is_red():
            if z.parent == z.parent.parent.left:
                y = z.parent.parent.right
                
                if y and y.is_red():
                    z.parent.color = Color.BLACK
                    y.color = Color.BLACK
                    z.parent.parent.color = Color.RED
                    z = z.parent.parent
                else:
                    if z == z.parent.right:
                        z = z.parent
                        self._left_rotate(z)
                    
                    z.parent.color = Color.BLACK
                    z.parent.parent.color = Color.RED
                    self._right_rotate(z.parent.parent)
            else:
                y = z.parent.parent.left
                
                if y and y.is_red():
                    z.parent.color = Color.BLACK
                    y.color = Color.BLACK
                    z.parent.parent.color = Color.RED
                    z = z.parent.parent
                else:
                    if z == z.parent.left:
                        z = z.parent
                        self._right_rotate(z)
                    
                    z.parent.color = Color.BLACK
                    z.parent.parent.color = Color.RED
                    self._left_rotate(z.parent.parent)
        
        if self._root:
            self._root.color = Color.BLACK
    
    def insert(self, key: T) -> bool:
        """插入 - O(log n)"""
        z = RBNode(key)
        y = None
        x = self._root
        
        while x:
            y = x
            if z.key < x.key:
                x = x.left
            elif z.key > x.key:
                x = x.right
            else:
                return False
        
        z.parent = y
        
        if not y:
            self._root = z
        elif z.key < y.key:
            y.left = z
        else:
            y.right = z
        
        z.left = None
        z.right = None
        z.color = Color.RED
        
        self._insert_fixup(z)
        self._size += 1
        return True
    
    def search(self, key: T) -> Optional[RBNode[T]]:
        """查找 - O(log n)"""
        current = self._root
        while current:
            if key == current.key:
                return current
            elif key < current.key:
                current = current.left
            else:
                current = current.right
        return None
    
    def _transplant(self, u: RBNode[T], v: Optional[RBNode[T]]) -> None:
        """替换子树"""
        if not u.parent:
            self._root = v
        elif u == u.parent.left:
            u.parent.left = v
        else:
            u.parent.right = v
        
        if v:
            v.parent = u.parent
    
    def _minimum(self, node: Optional[RBNode[T]]) -> Optional[RBNode[T]]:
        while node and node.left:
            node = node.left
        return node
    
    def _delete_fixup(self, x: Optional[RBNode[T]]) -> None:
        """删除修复"""
        while x and x != self._root and x.is_black():
            if x == x.parent.left:
                w = x.parent.right
                
                if w and w.is_red():
                    w.color = Color.BLACK
                    x.parent.color = Color.RED
                    self._left_rotate(x.parent)
                    w = x.parent.right
                
                if (not w.left or w.left.is_black()) and \
                   (not w.right or w.right.is_black()):
                    w.color = Color.RED
                    x = x.parent
                else:
                    if not w.right or w.right.is_black():
                        if w.left:
                            w.left.color = Color.BLACK
                        w.color = Color.RED
                        self._right_rotate(w)
                        w = x.parent.right
                    
                    w.color = x.parent.color
                    x.parent.color = Color.BLACK
                    if w.right:
                        w.right.color = Color.BLACK
                    self._left_rotate(x.parent)
                    x = self._root
            else:
                w = x.parent.left
                
                if w and w.is_red():
                    w.color = Color.BLACK
                    x.parent.color = Color.RED
                    self._right_rotate(x.parent)
                    w = x.parent.left
                
                if (not w.right or w.right.is_black()) and \
                   (not w.left or w.left.is_black()):
                    w.color = Color.RED
                    x = x.parent
                else:
                    if not w.left or w.left.is_black():
                        if w.right:
                            w.right.color = Color.BLACK
                        w.color = Color.RED
                        self._left_rotate(w)
                        w = x.parent.left
                    
                    w.color = x.parent.color
                    x.parent.color = Color.BLACK
                    if w.left:
                        w.left.color = Color.BLACK
                    self._right_rotate(x.parent)
                    x = self._root
        
        if x:
            x.color = Color.BLACK
    
    def delete(self, key: T) -> bool:
        """删除 - O(log n)"""
        z = self.search(key)
        if not z:
            return False
        
        y = z
        y_original_color = y.color
        
        if not z.left:
            x = z.right
            self._transplant(z, z.right)
        elif not z.right:
            x = z.left
            self._transplant(z, z.left)
        else:
            y = self._minimum(z.right)
            y_original_color = y.color
            x = y.right
            
            if y.parent == z:
                if x:
                    x.parent = y
            else:
                self._transplant(y, y.right)
                y.right = z.right
                y.right.parent = y
            
            self._transplant(z, y)
            y.left = z.left
            y.left.parent = y
            y.color = z.color
        
        if y_original_color == Color.BLACK and x:
            self._delete_fixup(x)
        
        self._size -= 1
        return True
    
    def inorder(self) -> List[T]:
        """中序遍历"""
        result = []
        
        def _traverse(node: Optional[RBNode[T]]):
            if node:
                _traverse(node.left)
                result.append(node.key)
                _traverse(node.right)
        
        _traverse(self._root)
        return result
    
    def _check_properties(self, node: Optional[RBNode[T]], black_count: int, 
                          path_black_count: List[int]) -> bool:
        """验证红黑性质"""
        if not node:
            path_black_count.append(black_count)
            return True
        
        if node.is_red():
            if (node.left and node.left.is_red()) or \
               (node.right and node.right.is_red()):
                return False
        
        new_black_count = black_count + (1 if node.is_black() else 0)
        
        return (self._check_properties(node.left, new_black_count, path_black_count) and
                self._check_properties(node.right, new_black_count, path_black_count))
    
    def is_valid_rbtree(self) -> bool:
        """验证红黑树性质"""
        if not self._root:
            return True
        
        if self._root.is_red():
            return False
        
        path_black_count = []
        if not self._check_properties(self._root, 0, path_black_count):
            return False
        
        return len(set(path_black_count)) == 1
    
    def __len__(self) -> int:
        return self._size
    
    def __contains__(self, key: T) -> bool:
        return self.search(key) is not None


def demonstrate_rbtree():
    """演示红黑树"""
    tree = RedBlackTree[int]()
    
    keys = [10, 20, 30, 15, 25, 5, 1, 35]
    for key in keys:
        tree.insert(key)
        print(f"插入 {key}: 有效={tree.is_valid_rbtree()}")
    
    print(f"\n中序遍历: {tree.inorder()}")
    print(f"树大小: {len(tree)}")
    
    tree.delete(20)
    print(f"\n删除 20 后: {tree.inorder()}")
    print(f"有效: {tree.is_valid_rbtree()}")


if __name__ == '__main__':
    demonstrate_rbtree()

14.4 平衡树对比分析

14.4.1 AVL树 vs 红黑树

定理 14.8(AVL树vs红黑树查找效率) AVL树的查找效率略高于红黑树。

证明

  • AVL树高度:$h_{AVL} \leq 1.44 \log_2 n$
  • 红黑树高度:$h_{RB} \leq 2 \log_2 n$

因此AVL树更平衡,查找路径更短。∎

定理 14.9(AVL树vs红黑树修改效率) 红黑树的插入删除效率高于AVL树。

证明

  • AVL树插入:最多 $O(\log n)$ 次旋转
  • 红黑树插入:最多 2 次旋转
  • AVL树删除:最多 $O(\log n)$ 次旋转
  • 红黑树删除:最多 3 次旋转

红黑树修改操作更稳定。∎

14.4.2 选择指南

特性AVL树红黑树
高度上界$1.44 \log n$$2 \log n$
查找效率更高略低
插入旋转最多 $O(\log n)$最多 2 次
删除旋转最多 $O(\log n)$最多 3 次
实现复杂度中等较高
典型应用数据库索引C++ STL、Java TreeMap

定理 14.10(平衡树选择原则)

  • 查找密集型应用:选择AVL树
  • 修改密集型应用:选择红黑树
  • 需要稳定性能:选择红黑树

14.5 其他平衡树结构

14.5.1 伸展树

定义 14.8(伸展树) 伸展树是一种自调整二叉搜索树,每次访问后将访问节点移动到根。

定理 14.11(伸展树均摊复杂度) 伸展树操作的均摊复杂度为 $O(\log n)$。

证明:使用势能方法。定义势能函数 $\Phi(T) = \sum_{x \in T} \log(size(x))$。

分析伸展操作的均摊代价,可证明为 $O(\log n)$。∎

14.5.2 B树

定义 14.9(B树) B树是多路平衡搜索树,满足:

  • 根节点至少有2个子节点
  • 每个内部节点有 $\lceil m/2 \rceil$ 到 $m$ 个子节点
  • 所有叶子在同一层

定理 14.12(B树高度) $n$ 个键、最小度数为 $t$ 的B树高度:

$$h \leq \log_t \frac{n+1}{2}$$


14.6 本章小结

14.6.1 核心定理总结

定理内容应用
定理 14.1平衡树高度 $O(\log n)$复杂度保证
定理 14.2AVL树高度上界性能分析
定理 14.3旋转保持BST性质正确性验证
定理 14.6红黑树高度上界性能分析
定理 14.7红黑树插入修复算法设计

14.6.2 平衡树复杂度对比

操作AVL树红黑树伸展树
查找$O(\log n)$$O(\log n)$$O(\log n)$ 均摊
插入$O(\log n)$$O(\log n)$$O(\log n)$ 均摊
删除$O(\log n)$$O(\log n)$$O(\log n)$ 均摊
旋转次数$O(\log n)$最多 3 次$O(\log n)$ 均摊

14.6.3 应用场景

场景推荐结构原因
数据库索引B+树磁盘友好
语言标准库红黑树修改稳定
内存数据库AVL树查找高效
缓存系统伸展树局部性好

14.7 习题

理论题

  1. 证明:AVL树的高度上界为 $1.44 \log_2 n$。

  2. 证明:红黑树的高度上界为 $2 \log_2(n+1)$。

  3. 分析AVL树删除操作的最坏情况旋转次数。

  4. 证明:旋转操作保持BST性质和中序遍历。

设计题

  1. 设计一个支持范围查询的平衡树。

  2. 实现一个支持持久化的红黑树。

实现题

  1. 实现AVL树的完整删除操作。

  2. 实现B树的插入和删除操作。


14.8 参考文献

  1. Adelson-Velsky, G., & Landis, E. M. (1962). An algorithm for the organization of information. Proceedings of the USSR Academy of Sciences, 146, 263-266.

  2. Bayer, R. (1972). Symmetric binary B-trees: Data structure and maintenance algorithms. Acta Informatica, 1(4), 290-306.

  3. Guibas, L. J., & Sedgewick, R. (1978). A dichromatic framework for balanced trees. FOCS, 8-21.

  4. Sleator, D. D., & Tarjan, R. E. (1985). Self-adjusting binary search trees. Journal of the ACM, 32(3), 652-686.

  5. Cormen, T. H., Leiserson, C. E., Rivest, R. L., & Stein, C. (2022). Introduction to Algorithms (4th ed.). MIT Press. Chapters 13-14.

  6. Knuth, D. E. (1998). The Art of Computer Programming, Volume 3: Sorting and Searching (2nd ed.). Addison-Wesley. Section 6.2.3.


下一章:第15章 图论基础理论

Python技术丛书 - 江苏省宿城中等专业学校