TreeMap

Posted smalljunjun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TreeMap相关的知识,希望对你有一定的参考价值。

按红黑树的结构来进行查询和插入。

查询的话就和普通的平衡二叉树一样。

这里我们先介绍红黑树的特点:

1.根节点为黑色

2.红色节点的子节点一定都是黑色

3.每个叶子节点都是黑色的(空节点)

4.从任一节点到其每个叶子的路径都包含相同数目的黑色节点。

红黑树和普通的平衡二插树最大的优势就是任何不平衡都可以在三次以内解决。

AVL 树是高度平衡的,频繁的插入和删除,会引起频繁的reblance,导致效率下降
红黑树不是高度平衡的,平衡因子是可能大于1的,算是一种折中,插入最多两次旋转,删除最多三次旋转

查询的话和普通的avL树是一样的,主要是插入:插入以后需要调整

public V put(K key, V value) {
    ......
    int cmp;
    Entry<K,V> parent;
    if (key == null)
        throw new NullPointerException();
    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);//创建并插入新的entry
    if (cmp < 0) parent.left = e;
    else parent.right = e;
    fixAfterInsertion(e);//调整
    size++;
    return null;
}

记住每次插入的节点一定是红色:

下面讨论插入后红黑树的变化:

主要的变化一般是先变色,再旋转:

//红黑树调整函数fixAfterInsertion()
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) {//如果y为null,则视为BLACK //都是红色都要变
                setColor(parentOf(x), BLACK);              // 情况1
                setColor(y, BLACK);                        // 情况1
                setColor(parentOf(parentOf(x)), RED);      // 情况1
                x = parentOf(parentOf(x));                 // 情况1
            } else {
                if (x == rightOf(parentOf(x))) {
                    x = parentOf(x);                       // 情况2
                    rotateLeft(x);                         // 情况2
                }
                setColor(parentOf(x), BLACK);              // 情况3
                setColor(parentOf(parentOf(x)), RED);      // 情况3
                rotateRight(parentOf(parentOf(x)));        // 情况3
            }
        } else {
            Entry<K,V> y = leftOf(parentOf(parentOf(x)));
            if (colorOf(y) == RED) {
                setColor(parentOf(x), BLACK);              // 情况4
                setColor(y, BLACK);                        // 情况4
                setColor(parentOf(parentOf(x)), RED);      // 情况4
                x = parentOf(parentOf(x));                 // 情况4
            } else {
                if (x == leftOf(parentOf(x))) {
                    x = parentOf(x);                       // 情况5
                    rotateRight(x);                        // 情况5
                }
                setColor(parentOf(x), BLACK);              // 情况6
                setColor(parentOf(parentOf(x)), RED);      // 情况6
                rotateLeft(parentOf(parentOf(x)));         // 情况6
            }
        }
    }
    root.color = BLACK;
}

具体的图参考:

https://www.cnblogs.com/CarpenterLee/p/5503882.html

在讨论删除:

https://www.cnblogs.com/qingergege/p/7351659.html

具体细节不用太去纠结。

再讨论一下B-树和B+树:

B-树:

1.关键字集合分布在整颗树中;

2.任何一个关键字出现且只出现在一个结点中;

3.搜索有可能在非叶子结点结束;

4.其搜索性能等价于在关键字全集内做一次二分查找;

 

B+树:

1.所有关键字都出现在叶子结点的链表中(稠密索引),且链表中的关键字恰好

是有序的;

2.不可能在非叶子结点命中;

3.非叶子结点相当于是叶子结点的索引(稀疏索引),叶子结点相当于是存储

(关键字)数据的数据层;

4.更适合文件索引系统;

以上是关于TreeMap的主要内容,如果未能解决你的问题,请参考以下文章

Java集合源代码剖析TreeMap源代码剖析

Java集合源代码剖析TreeMap源代码剖析

TreeMap - 源代码学习笔记

TreeMap实现原理

Scala中的TreeMap键和迭代

Java集合框架 Map接口实现类--TreeMap的使用 & TreeMap和TreeSet的关系