红黑树——Java

红黑树

红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的。
在这里插入图片描述

红黑树的性质

  1. 每个结点不是红色就是黑色;
  2. 根节点是黑色的 ;
  3. 如果一个节点是红色的,则它的两个孩子结点是黑色的 ;
  4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点 ;
  5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点);

满足上面的性质,红黑树就能保证:最长边的长度<=2*最短边的长度,红黑树中的平衡是一种相对平衡,而不像AVL树那样绝对平衡。红黑树中插入/查找的时间复杂度也是O(log(N))

红黑树节点的定义

class RBTreeNode{
   RBTreeNode left = null;
   RBTreeNode right = null;
   RBTreeNode parent = null;
   COLOR color = RED;    // 节点的颜色
   int val;
   
   public RBTreeNode(int val){
       this.val = val;
  }
}
1 红黑树的查找

同二叉搜索树相同。

2 红黑树的插入(插入的节点颜色一定是红色的)

红黑树是在二叉搜索树的基础上加上其平衡限制条件,因此红黑树的插入可分为两步:
(1). 按照二叉搜索的树规则插入新节点.
(2). 检测新节点插入后,红黑树的性质是否造到破坏.
下面分三种情况去讨论:

  • 插入的节点为根节点。(根必须是黑色的,改下颜色即可)
  • 插入节点的父节点是黑色的。(无需调整,插入结束)
  • 插入节点的父节点是红色的。(红色不能相邻,需要进一步调整,再分情况)

针对父节点是红色的情况:
1)其父(parent)节点有兄弟(brother)节点存在且是红色的:
此时只需将其parent.parent改为红色,parent,brother改为黑色即可。因为parent.paprent改为了红色,所以需要继续递归向上调整
在这里插入图片描述

2)其父节点没有brother节点,或者brother节点为黑色
A. 同边的情况(右旋或者左旋):
此时需要将p.p右旋,并将parent改为黑色,p.p改为红色。
在这里插入图片描述
对于brother为黑色的这种情况,可推知cur一定不是新插入的节点,而是在调整过程中变红的节点(如果是新插入的节点,那么原来的的树不满足“每个路径上的黑色节点相同”这一性质,所以不成立)。
在这里插入图片描述
所以这种情况下,cur下面应该带有子树。对p.p右旋,prent改黑色,p.p改红色。

在这里插入图片描述
B. 不同边的情况(右旋或者左旋)
先对parent左旋,变为同边的情况,操作同1)中所述。
在这里插入图片描述

3 AVL树和红黑树的比较

红黑树和AVL树都是高效的平衡二叉树,增删改查的时间复杂度都是O(log(N)),红黑树不追求绝对平衡,其只需保证最长路径不超过最短路径的2倍,相对而言,降低了插入和旋转的次数,所以在经常进行增删的结构中性能比AVL树更优,而且红黑树实现比较简单,所以实际运用中红黑树更多AVL树的查找性能略优,红黑树的插入删除性能略优。 java集合框架中的:TreeMap、TreeSet底层使用的就是红黑树.

4 红黑树插入举例:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5 TreeMap源码:

红黑树的插入:

public V put(K key, V value) {
    Entry<K,V> t = root;
    if (t == null) {
        compare(key, key); // type (and possibly null) check

        root = new Entry<>(key, value, null);
        size = 1;
        modCount++;
        return null;
    }
    int cmp;
    Entry<K,V> parent;
    // split comparator and comparable paths
    Comparator<? super K> cpr = comparator;
    if (cpr != null) {
        do {
            parent = t;
            cmp = cpr.compare(key, t.key);
            if (cmp < 0)
                t = t.left;
            else if (cmp > 0)
                t = t.right;
            else
                return t.setValue(value);
        } while (t != null);
    }
    else {
        if (key == null)
            throw new NullPointerException();
        @SuppressWarnings("unchecked")
            Comparable<? super K> k = (Comparable<? super K>) key;
        do {
            parent = t;
            cmp = k.compareTo(t.key);
            if (cmp < 0)
                t = t.left;
            else if (cmp > 0)
                t = t.right;
            else
                return t.setValue(value);
        } while (t != null);
    }
    Entry<K,V> e = new Entry<>(key, value, parent);
    if (cmp < 0)
        parent.left = e;
    else
        parent.right = e;
    fixAfterInsertion(e);
    size++;
    modCount++;
    return null;
}

插入之后的调整:

/** From CLR */
private void fixAfterInsertion(Entry<K,V> x) {
    x.color = RED;

    while (x != null && x != root && x.parent.color == RED) {
        if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
            Entry<K,V> y = rightOf(parentOf(parentOf(x)));
            if (colorOf(y) == RED) {
                setColor(parentOf(x), BLACK);
                setColor(y, BLACK);
                setColor(parentOf(parentOf(x)), RED);
                x = parentOf(parentOf(x));
            } else {
                if (x == rightOf(parentOf(x))) {
                    x = parentOf(x);
                    rotateLeft(x);
                }
                setColor(parentOf(x), BLACK);
                setColor(parentOf(parentOf(x)), RED);
                rotateRight(parentOf(parentOf(x)));
            }
        } else {
            Entry<K,V> y = leftOf(parentOf(parentOf(x)));
            if (colorOf(y) == RED) {
                setColor(parentOf(x), BLACK);
                setColor(y, BLACK);
                setColor(parentOf(parentOf(x)), RED);
                x = parentOf(parentOf(x));
            } else {
                if (x == leftOf(parentOf(x))) {
                    x = parentOf(x);
                    rotateRight(x);
                }
                setColor(parentOf(x), BLACK);
                setColor(parentOf(parentOf(x)), RED);
                rotateLeft(parentOf(parentOf(x)));
            }
        }
    }
    root.color = BLACK;
}

里面封装了很多方法,如取该节点的父节点:

private static <K,V> Entry<K,V> parentOf(Entry<K,V> p) {
    return (p == null ? null: p.parent);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值