TreeMap源码分析

TreeMap继承关系,和HashMap同继承于AbstractMap,属于兄弟关系。

public class TreeMap<K,V>
    extends AbstractMap<K,V>
    implements NavigableMap<K,V>, Cloneable, java.io.Serializable

-1. 基于 NavigableMap 实现的红黑树

-2. 按 natrual ordering(Comparator==null,默认) 或者 Comparator 定义的次序排序

-3. 基本操作containsKey,get,put 有 log(n) 的时间复杂度

-4. 非线程安全

同步:SortedMap m = Collections.synchronizedSortedMap(new TreeMap(...));

红黑树节点类型,默认为黑

static final class Entry<K,V> implements Map.Entry<K,V> {
    K key;
    V value;
    Entry<K,V> left = null;
    Entry<K,V> right = null;
    Entry<K,V> parent;
    boolean color = BLACK;
    ...
}

containsKey方法:

public boolean containsKey(Object key) {
    return getEntry(key) != null;
}
final Entry<K,V> getEntry(Object key) {
    // Offload comparator-based version for sake of performance
    if (comparator != null)
        return getEntryUsingComparator(key);
    if (key == null)
        throw new NullPointerException();
    Comparable<? super K> k = (Comparable<? super K>) key;
    Entry<K,V> p = root;
    //与二叉查找树的查找方式类似
    while (p != null) {
        int cmp = k.compareTo(p.key);
        if (cmp < 0)
            p = p.left;
        else if (cmp > 0)
            p = p.right;
        else
            return p;
    }
    return null;
}

containsValue方法:

public boolean containsValue(Object value) {
    for (Entry<K,V> e = getFirstEntry(); e != null; e = successor(e))
        if (valEquals(value, e.value))
            return true;
    return false;
}

找到了树中最左边的结点,如果左子树中的值小于右子树,这就意味是第一个比较的结点是最小的结点

final Entry<K,V> getFirstEntry() {
    Entry<K,V> p = root;
    if (p != null)
        while (p.left != null)
            p = p.left;
    return p;
}

successor 其实就是一个结点的下一个结点,所谓下一个,是按次序排序后的下一个结点。从代码中可以看出,如果右子树不为空,就返回右子树中最小结点。如果右子树为空,就要向上回溯了

static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) {
    if (t == null)
        return null;
    else if (t.right != null) {
        Entry<K,V> p = t.right;
        while (p.left != null)
            p = p.left;
        return p;
    } else {
        Entry<K,V> p = t.parent;
        Entry<K,V> ch = t;
        while (p != null && ch == p.right) {
            ch = p;
            p = p.parent;
        }
        return p;
    }
}

final Entry<K,V> getCeilingEntry(K key):找一个 x.key >= key 的元素,并且 x是满足条件的元素中最小的。

public V put(K key, V value):如果树是空的,那么创建根结点。否则就要在树中插入结点如果 key 在树中,就 setValue 设置新值,否则,插入新结点。插入后调用fixAfterInsertion调整平衡性。

TreeMap 删除节点用被删除节点的右子树中最小节点与被删节点交换的方式进行维护。

红黑树(Red Black Tree) 是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。

性质1. 节点是红色或黑色。

性质2. 根节点是黑色。

性质3. 每个叶节点(NIL节点,空节点)是黑色的。

性质4. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)。

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

从根节点到叶子节点的路径中包含的黑色节点数被称为树的“黑色高度(black-height)”。

红黑树中最长路径就是一条红黑交替的路径。

黑色高度为 N 的红黑树,从根到叶子节点的最短路径长度为 N-1,最长路径长度为 2 * (N-1)。

红黑树并不是真正的平衡二叉树,但在实际应用中,红黑树的统计性能要高于平衡二叉树,但极端性能略差。

但是在Java 实现的红黑树将使用 null 来代表空节点,因此遍历红黑树时将看不到黑色的叶子节点,反而看到每个叶子节点都是红色的

时间: 2024-12-20 07:26:10

TreeMap源码分析的相关文章

Java集合系列之TreeMap源码分析

一.概述 TreeMap是基于红黑树实现的.由于TreeMap实现了java.util.sortMap接口,集合中的映射关系是具有一定顺序的,该映射根据其键的自然顺序进行排序或者根据创建映射时提供的Comparator进行排序,具体取决于使用的构造方法.另外TreeMap中不允许键对象是null. 1.什么是红黑树? 红黑树是一种特殊的二叉排序树,主要有以下几条基本性质: 每个节点都只能是红色或者黑色 根节点是黑色 每个叶子节点是黑色的 如果一个节点是红色的,则它的两个子节点都是黑色的 从任意一

HashMap与TreeMap源码分析

1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Java这么久,也写过一些小项目,也使用过TreeMap无数次,但到现在才明白它的实现原理).因此本着"不要重复造轮子"的思想,就用这篇博客来记录分析TreeMap源码的过程,也顺便瞅一瞅HashMap. 2. 继承结构 (1) 继承结构 下面是HashMap与TreeMap的继承结构: pu

死磕 java集合之TreeMap源码分析(四)-内含彩蛋

欢迎关注我的公众号"彤哥读源码",查看更多源码系列文章, 与彤哥一起畅游源码的海洋. 二叉树的遍历 我们知道二叉查找树的遍历有前序遍历.中序遍历.后序遍历. (1)前序遍历,先遍历我,再遍历我的左子节点,最后遍历我的右子节点: (2)中序遍历,先遍历我的左子节点,再遍历我,最后遍历我的右子节点: (3)后序遍历,先遍历我的左子节点,再遍历我的右子节点,最后遍历我: 这里的前中后都是以"我"的顺序为准的,我在前就是前序遍历,我在中就是中序遍历,我在后就是后序遍历. 下

死磕 java集合之TreeMap源码分析(一)

欢迎关注我的公众号"彤哥读源码",查看更多源码系列文章, 与彤哥一起畅游源码的海洋. 简介 TreeMap使用红黑树存储元素,可以保证元素按key值的大小进行遍历. 继承体系 TreeMap实现了Map.SortedMap.NavigableMap.Cloneable.Serializable等接口. SortedMap规定了元素可以按key的大小来遍历,它定义了一些返回部分map的方法. public interface SortedMap<K,V> extends Ma

死磕 java集合之TreeMap源码分析(三)- 内含红黑树分析全过程

欢迎关注我的公众号"彤哥读源码",查看更多源码系列文章, 与彤哥一起畅游源码的海洋. 删除元素 删除元素本身比较简单,就是采用二叉树的删除规则. (1)如果删除的位置有两个叶子节点,则从其右子树中取最小的元素放到删除的位置,然后把删除位置移到替代元素的位置,进入下一步. (2)如果删除的位置只有一个叶子节点(有可能是经过第一步转换后的删除位置),则把那个叶子节点作为替代元素,放到删除的位置,然后把这个叶子节点删除. (3)如果删除的位置没有叶子节点,则直接把这个删除位置的元素删除即可.

TreeMap 源码分析

TreeMap 1)TreeMap 是基于红黑树的 NavigableMap 接口实现类. 2)TreeMap 根据键的自然顺序或构造时提供的比较器进行键的排序. 3){@code containsKey}, {@code get}, {@code put} and {@code remove} 方法的时间复杂度为 log(n). 4)TreeMap 不是线程同步的,多线程并发访问 TreeMap 并且至少有一个线程修改了其结构,则它必须在外部实现同步. SortedMap m = Collec

java.util.TreeMap源码分析

TreeMap的实现基于红黑树,排列的顺序根据key的大小,或者在创建时提供的比较器,取决于使用哪个构造器. 对于,containsKey,get,put,remove操作,保证时间复杂度为log(n). TreeMap的顺序与equals方法保持一致,这样才能遵守Map和SortMap的约定. 实现非同步,运行在多线程环境下,要进行外部同步,或者调用SortedMap m = Collections.synchronizedSortedMap(new TreeMap(...));方法得到一个同

死磕 java集合之TreeMap源码分析(二)

插入元素 插入元素,如果元素在树中存在,则替换value:如果元素不存在,则插入到对应的位置,再平衡树. 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;

TreeMap源码分析之一 —— 排序二叉树、平衡二叉树、红黑树

一.排序二叉树(BST树) 1.排序二叉树的定义 排序二叉树,Binary Sort Tree 排序二叉树要么是一棵空二叉树,要么是具有下列性质的二叉树: (1)若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值: (2)若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值: (3)它的左.右子树也分别为排序二叉树. 按中序遍历排序二叉树可以得到由小到大的有序序列. 比如 2.排序二叉树的插入和删除 二.平衡二叉树(Balanced Binary Tree,AVL树) 三.红黑