数据结构-红黑树

红黑树

红黑树的五大特性:

  1. 根节点是【黑色】
  2. 【红色】节点的子节点一定都是【黑色】,但是黑色节点的子节点可以是红色和黑色
  3. 每个叶子节点都是黑色的空节点(NIL),因为叶子节点不存储数据
  4. 任意一个节点到叶子节点的路径上所包含的【黑色】节点的数量是相同的
    这个也称之为【黑色完美平衡】
  5. 新插入的节点必须是【红色】
    为什么?如果新插入的节点是【黑色】,那不管是在插入到那里,一定会破坏黑色完美平衡的

根据以上性质可以推断出:所以红黑树左右子树高度差最大为2倍
——左边n个黑色节点,右边n个黑色节点,然后两个黑色节点中间插入一个红色节点。所以右边n黑色+n红色

为什么红黑树被广泛应用?

二叉搜索树bst极端情况下时间复杂度退化为O(n)

平衡二叉树AVL 虽然效率非常高,但是每次插入、删除都要做调整,所以对于有频繁的插入、删除操作的数据集合,使用 AVL 树的代价就有点高了。

红黑树即不像二叉查找树那样存在复杂度退化的问题,
也不会像完成平衡二叉树那样为了保证完全的平衡而过多的旋转调整。
算是在查找和增删之间取了很好的平衡。
红黑树的高度近似 log2n,增删改查操作的时间复杂度都是 O(logn)

应用场景:

  • java的hashmap、 TreeMap 、TreeSet 底层用到红黑树

  • c++ stl中的map、set底层就是红黑树

  • epoll在内核中的实现,用红黑树管理文件描述符fd

插入过程的旋转变色

详细图文

1、当前节点为空,直接插入即可
2、插入的节点已经存在,直接替换即可
3、插入节点的父节点为【黑色节点】,找到父节点,直接插入即可。因为这个树本来就是黑色完美平衡了,再新插入一个新的红色节点,并不会破坏树的平衡以及红黑树的特性。

4、插入节点的父节点为红色
现在,插入的节点的父节点为红色节点,而红色节点一定不可能为根节点,所以可以推断出新插入节点的父节点一定还有父节点
在这里插入图片描述
那现在很显然违反了上面的特性 3( 每个【红色】节点的两个子节点一定都是【黑色】),而现在是两个红色节点相连了,这个该怎么处理?此时又继续拆分不同的情况了

第 4-1 种情况:插入节点的叔叔节点存在,且为红色
这个时候你看的树大致是这样子的结构
在这里插入图片描述
解决办法:① 将 P 和 U 变成黑色;② 将 PP 变成 红色
如下图:
在这里插入图片描述
第 4-2 种情况:叔叔节点不存在,且插入节点的【父节点】是插入节点爷爷节点的【左子节点】
在这里插入图片描述

  • 第 4-2-1 种情况:
    插入节点为其父节点的左子节点,也即 LL 双红色的情况(第一个 L 表示插入节点的父节点,第二个 L 表示插入节点)
    这种情况的完整的变换流程如下:

在这里插入图片描述

  • 第 4-2-2 种情况:
    插入节点为其父节点的右子节点,也即 LR 双红色的情况
    其完成的变换流程如下:
    在这里插入图片描述
    第 4-3 种情况:叔叔节点不存在,且插入节点的【父节点】是插入节点爷爷节点的【右子节点】
    在这里插入图片描述
    这种情况依旧是继续区分插入节点是其父节点的左子节点还是右子节点

  • 第 4-3-1 种情况:
    插入节点为其父节点的右子节点,也即 RR 双红色的情况(第一个 R 是插入节点的父节点,第二个 R 是插入节点)
    其整个转换流程是这样的
    在这里插入图片描述

  • 第 4-3-2 种情况:
    插入节点为其父节点的左子节点,也即 RL 双红色的情况
    其完整的转换流程是这样子的:
    在这里插入图片描述

### Java 中红黑树数据结构实现与应用 #### 红黑树简介 红黑树是一种自平衡二叉查找树,在计算机科学中用于高效地存储和检索键值对。该数据结构的特点在于其能够自动调整节点位置来维持一定的平衡条件,从而保证最坏情况下的时间复杂度为 O(log n)[^1]。 #### 平衡特性对比 相较于 AVL 树而言,尽管两者都致力于维护二叉查找树的高度接近于最小可能高度,但是由于红黑树对于旋转次数的要求较低,因此在频繁发生插入或删除的情况下表现更优;而像 `TreeMap` 和 `TreeSet` 这样的集合类正是利用这一点实现了高效的增删改查功能[^2]。 #### 关键属性定义 为了满足上述提到的性质,每棵红黑树中的结点除了拥有指向左右子树以及父辈指针外还需要额外记录颜色信息(红色/黑色),具体如下所示: ```java private static final boolean RED = false; private static final boolean BLACK = true; static class Node<K,V> { K key; // 存储的关键字 V value; // 对应关键字所映射的对象 Node<K,V> left; // 左孩子引用 Node<K,V> right; // 右孩子引用 Node<K,V> parent;// 父亲引用 boolean color; // 颜色标记 public Node(K key, V value, Node<K,V> parent){ this.key=key; this.value=value; this.parent=parent; this.color=RED; // 新加入的节点默认设为红色 } } ``` #### 插入操作逻辑 当向一棵已有的红黑树内添加新元素时,会先按照普通的 BST 方式找到合适的位置并创建新的叶子节点。之后再依据一系列规则判断是否需要执行重涂色或是旋转变换以恢复整棵树应有的形态特征。 - 如果当前新增加的是根,则直接将其变为黑色; - 若祖父存在且叔叔也为红色,则将父亲、叔叔均改为黑色并将祖父变更为红色继续向上处理; - 当仅有单侧兄弟呈红色状态时可通过一次左(右)转使得双亲成为临时性的“假”根以便后续统一调整; - 剩余情形下只需简单交换父子间染色即可完成修复工作。 以上过程可以概括成一段伪代码形式表示出来: ```pseudo function insertFixup(node) if node is root then set its color to black and return. while (node != null && node's parent is red) // 处理违反红黑树特性的几种场景... end while ``` 实际上完整的算法较为复杂,涉及到多个分支路径的选择问题,这里仅给出大致思路供理解参考之用。 #### 删除操作概述 移除某个指定项的过程同样遵循着相似的原则——即先依照普通二叉搜索树的方式定位目标对象所在位置,并考虑三种不同类型的状况分别采取相应的措施加以应对:如果待消除的目标恰好处于末端处那么可以直接摘掉它而不影响其他部分;反之则需寻找合适的替代品填补空缺后再做进一步讨论。 值得注意的是在整个过程中可能会引入一些暂时不符合标准的情况,这就要求我们及时作出必要的修正动作直至最终达到稳定为止。 #### 应用实例分析 正如前面提及的一样,红黑树广泛应用于各种编程语言的标准库当中作为内部机制支撑起诸如有序表之类的抽象容器类型。例如在 JDK8 版本以后版本里头,`HashMap` 的链地址法解决哈希冲突方案便采用了基于红黑树优化后的链表结构,以此提高极端情况下访问效率的同时兼顾了空间利用率方面的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值