title: 红黑树原理
红黑树提纲
- 2-3树介绍
- 红黑树
该博客都是读者具备二分树基础知识前提下写的(不清楚的不要看下面的内容了,看了也不会明白多少的…)
下面都统一用RBTree表示红黑树。
RBTree很多人都觉得难,其实我刚听到的时候也觉得难。因为大家都说难。。。哈哈~开个玩笑
RBTree其实并没有说的那么难,RBTree是23Tree的变种版本。
所以正常的学习流程应该是先从23Tree学起,然后再去理解红黑树就是一件非常简单的事情了。
RBTree是Robert Sedgewick 这位老哥发明,他老师是唐纳德有兴趣可以搜搜唐纳德是何人。
我这篇博客仅仅只是翻译一点Robert Sedgewick的文档。
这是PDF地址看了这个基本懂了
RedBlack.pdf
红黑树数据结构在线演示
其他数据结构及算法
美团红黑树博客
美团的这篇写的不错,但是我觉得并不是给人看的。讲的那么复杂干嘛。。。。
2-3树介绍
首先需要明白理解23树对于理解红黑树和B树都是有好处。
那么23树是什么?
23树满足二分搜索树的基本性质。
我们看23树的key的种类。
2-node: one key, two children.一个key值,两个儿子节点
3-node: two keys, three children。两个key值,三个儿子节点
当超过3个node的时候会进行树重构,节点上升。
23树的基本定义就是上面这些了。
那么23树的查找怎么做了?
1.比较要查找的key与当前节点中的key值
2.根据key值选择要查找的key所存在的子树区间
3.重复上述步骤(递归实现),直到查找到key
插入的步骤怎么做了?
首先,如果是向一个2-node插入节点的话,那么直接将它转换为3-node就可以了
然后,如果向3-node插入怎么办了?此时已经达到了节点最大值,无法插入数据了。只能做节点变换,一般直接将中间的节点上移到父节点此时就可以插入数据了。
如果不清楚的话先看看上面的PDF中的234树,因为主要讲红黑树
红黑树
这边我要实现的红黑树是一个左倾红黑树,也是相对传统红黑树个人觉得升级的更简洁的红黑树。
首先我们看一下红黑树的定义
1.每个节点或者是黑色,或者是红色。
2.根节点是黑色。
3.每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!]
4.如果一个节点是红色的,则它的子节点必须是黑色的。
5.从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点
下面看一张红黑树的实例图(绝对的标准!!!!)
上面的是传统的红黑树而我们要实现的是左倾的红黑树。
与上面仅仅多了一个条件
所有的红色Node都在左边。
看一下具体的实现如下图。
借用一下liuyubobobo波波老师的PPT截了一张图。(懒得画了~哈哈)
看图肯定觉得传统红黑和左倾里面数据都不一样的位置了。
但是可以保证的是左倾实现代码没有传统复杂并且功能一样,有什么理由拒绝了?
下面咱们自己实现一个红黑树。
首先我参考了Doug Lea的代码也参考了Robert Sedgewick顺带的也参考了bobo老师的代码
bobo老师参考的Robert Sedgewick
他们三个人实现了还是有些细节区别。
比如Robert Sedgewick和bobo都喜欢用递归。
Doug Lea喜欢用死循环。
这些都是有原因的,个人还是觉得Doug Lea更偏向于生产代码。
比较递归层次多一点就stackoverflow了,不过递归也有好处代码简洁写起来也简单。
所以我的代码循环和递归都会用~
我想了一下我还是在代码里面添加注释的方式讲解好了。
/**
* @ClassName LRBTree
* @Description ToDo
* @Author Allen
* @Date 2018/12/16 3:01
* @Version
*/
public class LRBTree<K extends Comparable <K>, V> {
private final RBTreeBase <K, V> rbTree;
abstract static class RBTreeBase<K extends Comparable <K>, V> {
//红黑常量
private static final boolean RED = true;
private static final boolean BLACK = false;
private Node <K, V> root;
private int size;
RBTreeBase() {
root = null;
size = 0;
}
V get(K key) {
Node <K, V> node = findNode(key);
return node == null ? null : node.value;
}
void put(K key, V value) {
Node <K, V> node = addNode(getRoot(), key, value);
setRoot(node);//因为默认添加的元素都是红色,当root元素的时候需要颜色翻转为黑
}
abstract Node <K, V> findNode(K key);
abstract Node <K, V> addNode(Node <K, V> node, K key, V value);
abstract V delete();
protected int getSize() {
return size;
}
protected int setSize() {
return size++;
}
protected boolean isEmpty() {
return size == 0;
}
protected Node <K, V> getRoot() {
return root;
}