再探红黑树

1 篇文章 0 订阅
1 篇文章 0 订阅

预备知识

  1. 二叉查找树、平衡树
  2. 2-3树

2-3 树

  • 2个键 3个结点
  • 平衡特性
    • 空链接到根结点的距离都相等
      • 这个可以通过构造2-3树时的各种插入过程进行理解
    • 当根结点分被分解为3个2-结点时,所有的空链接到根结点路径长度才会加1
  • 树的组成
    1. 2结点
      • 1个键,左链子树的值小于该键值,右边子树的值大于该键值
    2. 3结点
      • 2个键,左链子树的值都小于该结点的键值,右链子树的值都大于该结点的键值,中间子树的值位于这两个键值中间
  • 无论如何构造,查找效率都是对数级别的
    • 二叉查找树,在构造为平衡二叉树的情况下,其查找效率时对数级别的,但是
    • 在最坏的情况下,其查找效率可以退缩到线性级别的
    • 使用2-3树平衡查找树,便可在任何构造情况下都是对数级别的
    • 2-3树的一种实际运用是红黑树,后文将会介绍

2-3树的操作

  • 查找

    1. 从根结点开始,判断键值是否相等,若相等则查找成功,否则根据所在区间在子树中继续查找
    2. 如果是个空链接,查找未命中
  • 插入

    1. 2-结点插入
      • 直接插入
    2. 只含3-结点
      • 先变成一个4结点,然后扩展成一个包含三3个2结点的2-3树
      • 此时树依旧平衡,所有空链接到根结点的距离都相等
    3. 2-结点为父结点的3-结点插入
      • 先变成一个4结点,扩展成包含3个2-结点的2-3子树,将子树的根结点与父亲结点合并得到最终的2-3平衡树
    4. 3-结点为父结点的3-结点插入
      • 在要插入的位置扩展成一个4结点,然后分解为包含3个2-结点的2-3子树
      • 接着,将子树根结点与父亲3-结点继续扩展和分解,直到遇到一个2结点或者到达根结点
    5. 分解根结点
      • 如果插入的路径上都是3-结点,则最终的根结点变成一个4-结点,此时分解这个4-结点
      • 此时与像只含3-结点的插入方法一致,最终树的高度加1,但依旧保持平衡,因为它的变换是根结点
    6. 总结
      • 局部性 除了相关的结点和链接之外不必检查或者修改其他的部分
      • 全局性 局部变化,不会影响树的全局有序性和平衡性,因为无论是
        1. 将一个4-结点分别成2-结点,并将父结点由2-结点变为3-结点
        2. 还是将3-结点变成一个临时的4-结点
        3. 或者最终分解了根结点,导致空链接到根结点的路径都加1,都保证了空链接到根结点的距离都相等
      • 生长模式: 2-3树由下向上生长,而标准的二叉树,是由上向下生长

2-3树的缺点

  • 需要维护两个不同类型的结点
    • 2-结点
    • 3-结点
  • 实现的代码量很大
    • 被查找键和结点中的每个键进行比较
    • 将链接和其他信息从一种结点复制到另一个结点
    • 将结点从一种数据类型转换到另一种数据结构,等等

红黑树 升级版二叉树,可以说是二叉查找树中的钢铁侠

  • 主要思想:用标准的二叉树和一些额外的信息来表示2-3树
    • 标准二叉查找树,完全由2-结点构成
    • 额外的信息,是用来替换3-结点的
  • 一种等价的定义如下:
    • 红链接均为左链接
    • 没有任何一个结点同时和两条红链接相连
    • 该树时完美平衡的,即任意空链接到根结点的距离相等
    • 红黑树,即是二叉查找树,也是2-3树,使用了各自的优点
      1. 二叉查找树中简洁高效的查找方法
      2. 2-3树中高效的平衡插入算法

操作

  • 当实现某些操作中可能会出现红色右链接或者两条连续的红链接,需要在操作完成之前进行旋转并修复

  • 与构造AVL平衡二叉查找树类似,在构造过程中需要进行旋转变换

    1. 左旋转 子树根结点的右链接为红色,且左子结点为黑色进行左旋转
    2. 右旋转 左子结点是红色的且左子结点的左子结点也是红色的,进行右旋转
    3. 如果左右子结点均为红色,进行颜色转换,当根结点由红变黑时,树的黑链接高度加1(相当于分解根结点了)。
  • 插入(新结点插入时,默认为红色,即父结点指向该结点的链接为红色)

    1. 向单个2-结点中插入
      • 向左插入
      • 向右插入
    2. 向树底部的2-结点插入
      • 正确三结点
      • 错误三结点
    3. 向一个双键树插入新键
      • 新键最大
      • 新键最小
      • 新键介于两者之间
    4. 向树底部的3-结点插入新键
      • 红键向上传递性
  • 左旋转参考代码

// 右链接为红色,左链接为黑色 进行左旋转
Node rotateLeft(Node h) {
	Node x = h.right;
    h.right = x.left;
    x.left = h;
    x.color = h.color; // h.color 可红可黑
    h.color = RED;
	x.N = h.N;
    H.n = 1 + size(h.left) + size(h.right);
    return x;
}
  • 右旋转参考代码
// 左子结点是红色的且左子结点的左子结点也是红色的,进行右旋转
Node rotateRight(Node h) {
	Node x = h.left;
	h.left = x.right;
	x.right = h;
	x.color = h.color;
	h.color = RED;
	x.N = h.N;
	h.N = 1 + size(h.left) + size(h.right);
	return x;
}
  • 颜色转换参考代码
void flipColors(Node h) {
	h.color = RED;
    h.left.color = BLACK;
    h.left.color = BLACK;
}
  • 数据结构
private static final boolean RED = true;
private static final boolean BLACK = false;

private class Node {
	Key key; // 键
    Value value; // 键关联的值
    Node left;
    Node right;
    int N; // 这颗子树中的结点总数
    boolead color; // 由父结点指向它链接的颜色
    
    Node(Key key, Value val, int N, boolean color) {
		this.key = key;
        this.value = value;
        this.N = N;
        this.color color;
    }
    
    private boolean isRead(Node x) {
    	if (x == null) return false;
        return x.color == RED;
    }
}

红黑树的性质

  • 研究红黑树的性质就是要检查对应的2-3树并对应的2-3树进行分析的过程。
  • 关于红黑树的几个命题:
    1. 一棵大小为N的红黑树的高度不会超过2lgN
    2. 一棵大小为N的红黑树中,跟结点到任意结点的平均长度为~1.00lgN
    3. 一下操作最坏情况下时对数级别的
      1. get()
      2. put()
      3. floor()
      4. ceiling()
      5. rank()
      6. select()
      7. deleteMin()
      8. deleteMax()
      9. delete()
      10. range()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值