TreeMap源码深究

简介
TreeMap集合是基于红黑树(Red-Black tree)的 NavigableMap实现。该集合最重要的特点就是可排序,该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序。Tree两张实现排序方法,一种方式是实现java.lang.Comparable接口,并实现其compareTo()方法。第二种方式是单独写一个类去实现java.util.Comparator接口,并实现compare()方法,然后创建实例并作为TreeMap的构造方法参数进行传参

TreeMap 类

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

这里有个特殊接口NavigableMap

TreeMap 属性

// 这是一个比较器,方便插入查找元素等操作
private final Comparator<? super K> comparator;
// 红黑树的根节点:每个节点是一个Entry
private transient Entry<K,V> root;
// 集合元素数量
private transient int size = 0;
// 集合修改的记录
private transient int modCount = 0;

TreeMap 构造函数

public TreeMap() {
    comparator = null;
}
public TreeMap(Comparator<? super K> comparator) {
    this.comparator = comparator;
}
public TreeMap(Map<? extends K, ? extends V> m) {
    comparator = null;
    putAll(m);
}
public TreeMap(SortedMap<K, ? extends V> m) {
    comparator = m.comparator();
    try {
        buildFromSorted(m.size(), m.entrySet().iterator(), null, null);
    } catch (java.io.IOException cannotHappen) {
    } catch (ClassNotFoundException cannotHappen) {
    }
}

从属性和构造函数可以看出,TreeMap没有用到数组槽,并且有一个Entry的root结点,它完全就是一颗树。

TreeMap 添加

public V put(K key, V value) {
    Entry<K,V> t = root;
    if (t == null) {//如果root为null 说明是添加第一个元素 直接实例化一个Entry 赋值给root
        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;//如果root不为null,说明已存在元素 
    // split comparator and comparable paths
    Comparator<? super K> cpr = comparator;
    if (cpr != null) { //如果比较器不为null 则使用比较器
        //找到元素的插入位置
        do {
            parent = t; //parent赋值
            cmp = cpr.compare(key, t.key);
            //当前key小于节点key 向左子树查找
            if (cmp < 0)
                t = t.left;
            else if (cmp > 0)//当前key大于节点key 向右子树查找
                t = t.right;
            else //相等的情况下 直接更新节点值
                return t.setValue(value);
        } while (t != null);
    }
    else { //如果比较器为null 则使用默认比较器
        if (key == null)//如果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;
}

红黑树逻辑有兴趣的看HashMap篇

TreeMap 重要内部类
Entry 类

static final class Entry<K,V> implements Map.Entry<K,V>

虽然TreeMap 内部结构是红黑树,但是他并没有使用使用HashMap中的TreeNode对象作为节点

Entry 属性

// 键
K key;
// 值
V value;
// 左节点
Entry<K,V> left;
// 右节点
Entry<K,V> right;
// 父节点
Entry<K,V> parent;
// 节点颜色
boolean color = BLACK;

Entry 构造函数

Entry(K key, V value, Entry<K,V> parent) {
    this.key = key;
    this.value = value;
    this.parent = parent;
}

Entry方法

public K getKey() {
    return key;
}
public V getValue() {
    return value;
}
public V setValue(V value) {
    V oldValue = this.value;
    this.value = value;
    return oldValue;
}
public boolean equals(Object o) {
    if (!(o instanceof Map.Entry))
        return false;
    Map.Entry<?,?> e = (Map.Entry<?,?>)o;

    return valEquals(key,e.getKey()) && valEquals(value,e.getValue());
}
public int hashCode() {
    int keyHash = (key==null ? 0 : key.hashCode());
    int valueHash = (value==null ? 0 : value.hashCode());
    return keyHash ^ valueHash;
}

Entry 自己的方法不多,维护树结构主要还是靠TreeMap,不像HashMap的TreeNode需要自己维护树结构

TreeSet 类

TreeSet描述的是Set的一种变体,可以实现排序等功能的集合,它在讲对象元素添加到集合中时会自动按照某种比较规则将其插入到有序的对象序列中,实际上它是对TreeMap的封装,同HashSet、LinkedHashSet一样,它使用TreeMap的键。

public class TreeSet<E> extends AbstractSet<E>
        implements NavigableSet<E>, Cloneable, java.io.Serializable

继承AbstractSet<E>抽象类,实现NavigableSet<E>接口

 

NavigableSet<E> 接口

public interface NavigableSet<E> extends SortedSet<E>

NavigableSet扩展了 SortedSet,可以获取一个最接近的元素。方法 lower、floor、ceiling 和 higher 分别返回小于、小于等于、大于等于、大于给定元素的元素,如果不存在这样的元素,则返回 null。

 

NavigableSet<E> 方法

// 返回此set中小于给定元素的最大元素,如果没有这样的元素,则返回NULL。
E lower(E e);
// 返回此集合中小于或等于给定元素的最大元素,如果没有这样的元素,则返回NULL。
E floor(E e);
// 返回此set中大于或等于给定元素的最小元素,如果没有这样的元素,则返回NULL。
E ceiling(E e);
// 返回此set中大于给定元素的最小元素,如果没有这样的元素,则返回NULL。
E higher(E e);
// 检索并删除第一个最小元素。如果没有这样的元素,则返回null。
E pollFirst();
// 检索并删除最后一个最高元素。如果没有这样的元素,则返回null。
E pollLast();
// 迭代器
Iterator<E> iterator();
// 返回此 set 中所包含元素的逆序视图。
NavigableSet<E> descendingSet();
// 以降序返回在此 set 的元素上进行迭代的迭代器。
Iterator<E> descendingIterator();
// 返回此 set 的部分视图,其元素范围从 fromElement 到 toElement。
NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
                       E toElement,   boolean toInclusive);
// 返回此 set 的部分视图,其元素小于(或等于,如果 inclusive 为 true)toElement。
NavigableSet<E> headSet(E toElement, boolean inclusive);
//  返回此 set 的部分视图,其元素大于(或等于,如果 inclusive 为 true)fromElement。
NavigableSet<E> tailSet(E fromElement, boolean inclusive);
// 返回此 set 的部分视图,其元素从 fromElement(包括)到 toElement(不包括)。
SortedSet<E> subSet(E fromElement, E toElement);
// 返回此 set 的部分视图,其元素严格小于 toElement。
SortedSet<E> headSet(E toElement);
// 返回此 set 的部分视图,其元素大于(或等于,如果 inclusive 为 true)fromElement。
SortedSet<E> tailSet(E fromElement);

 

SortedSet<E> 接口

public interface SortedSet<E> extends Set<E>

SortedSet 根据比较器对元素进行排序,如果比较器为空,则自然排序

 

SortedSet<E> 方法

// 获取比较器
Comparator<? super E> comparator();
// 获取两个元素直接的元素集
SortedSet<E> subSet(E fromElement, E toElement);
// 获取之前的元素
SortedSet<E> headSet(E toElement);
// 获取之后的元素
SortedSet<E> tailSet(E fromElement);
// 第一个元素
E first();
// 最后一个元素
E last();

 

TreeSet 属性

// NavigableMap对象(NavigableMap下就一个TreeMap实现)
private transient NavigableMap<E,Object> m;
// 固定常量作为Map值
private static final Object PRESENT = new Object();

NavigableMap可以看TreeMap篇

 

TreeSet 构造函数

TreeSet(NavigableMap<E,Object> m) {
    this.m = m;
}
public TreeSet() {
    this(new TreeMap<E,Object>());
}
public TreeSet(Comparator<? super E> comparator) {
    this(new TreeMap<>(comparator));
}
public TreeSet(Collection<? extends E> c) {
    this();
    addAll(c);
}
public TreeSet(SortedSet<E> s) {
    this(s.comparator());
    addAll(s);
}

TreeSet实际上用的是TreeMap,TreeMap内部结构是红黑树,这里只用了它的键,值为固定常量

 

TreeSet 基础方法

// 长度
public int size() {
    return m.size();
}
// 是否为空
public boolean isEmpty() {
    return m.isEmpty();
}
// 是否存在
public boolean contains(Object o) {
    return m.containsKey(o);
}
// 添加
public boolean add(E e) {
    return m.put(e, PRESENT)==null;
}
// 删除
public boolean remove(Object o) {
    return m.remove(o)==PRESENT;
}
// 清空
public void clear() {
    m.clear();
}

说白了就是用TreeMap的key

 

TreeSet 搜索

// 第一个元素
public E first() {
    return m.firstKey();
}
// 最后一个元素
public E last() {
    return m.lastKey();
}
// 获取最接近e的节点(小于等于)
public E lower(E e) {
    return m.lowerKey(e);
}
// 获取最接近e的节点(大于等于)
public E floor(E e) {
    return m.floorKey(e);
}

TreeSet 搜索都是基于TreeMap红黑树搜索,其他方法可以参考TreeMap篇。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

源码猎人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值