TreeMap源码分析

TreeMap类图

TreeMap是java.util包下的Map接口下的一个子类,也是我们常用的容器,是一个有序的,非线程安全的key-value映射容器。

  • AbstractMap抽象类:Map接口下的默认实现抽象类,实现一些Map通用的方法。
  • Cloneable接口:实现对象拷贝必须要实现的接口。
  • Serializable接口:实现序列化必须要实现的接口。
  • NavigableMap接口:此接口实现了Sorted接口,而Sorted接口里面定义了一个Comparator接口,定义排序相关操作。

TreeMap属性

以上便是TreeMap的属性,下面一一分析:

comparator

    private final Comparator<? super K> comparator;

比较器,用于定义key的排序算法,构造函数时可传入。

root

private transient Entry<K,V> root;

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

树的根节点,Entry是一个内部类,记录key、value、左孩子、右孩子和父节点、该节点的颜色(红或黑)等信息

size 

    private transient int size = 0;

容器中元素的数量。

modCount 

    private transient int modCount = 0;

修改次数,用于迭代器快速失败机制。

entrySet

    private transient EntrySet entrySet;

保存所有的key-value键值对

serialVersionUID 

    private static final long serialVersionUID = 919286545866124006L;

序列化ID

TreeMap常用API

    public TreeMap() {
        comparator = null;
    }

    public TreeMap(Comparator<? super K> comparator) {
        this.comparator = comparator;
    }

    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) {
        }
    }

    public TreeMap(Map<? extends K, ? extends V> m) {
        comparator = null;
        putAll(m);
    }

TreeMap的构造函数

  • 空参:comparator属性为null,默认采用自然排序
  • Comparator参数:传入一个Comparator接口的实现类,定义相关的排序方法compare
  • SortedMap参数:传入SortedMap接口的实现类
  • Map参数:将一个别的Map集合转化为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;
    }

put方法:向容器中插入一个元素,返回

  • 首先判断之前的根节点是否为null,如果是,则检查一下key的类型(可能为null),然后将要插入的节点设置为根节点,返回null
  • 如果之前的根节点不为null,则先判断构造函数是否传入comparator,如果传入,则调用传入的comparator去进行遍历树比较key确定插入位置,如果没有传入,则判断key是否实现了Comparable接口,如果实现了,则调用key里定义的排序算法进行遍历树比较key确定插入位置,如果都没有,则插入根节点的右子树位置,返回null。最后size++,modcount+(modcount是修改的次数,用于迭代的快速失败机制)

由此可以看出,TreeMap实现key有序的机制是依靠创建TreeMap时传入的Comparator的实现类或者依靠key实现Comparable接口来定义相关的排序算法,优先使用构造函数传入的Comparator。

    public V get(Object key) {
        Entry<K,V> p = getEntry(key);
        return (p==null ? null : p.value);
    }

    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();
        @SuppressWarnings("unchecked")
            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;
    }

    final Entry<K,V> getEntryUsingComparator(Object key) {
        @SuppressWarnings("unchecked")
            K k = (K) key;
        Comparator<? super K> cpr = comparator;
        if (cpr != null) {
            Entry<K,V> p = root;
            while (p != null) {
                int cmp = cpr.compare(k, p.key);
                if (cmp < 0)
                    p = p.left;
                else if (cmp > 0)
                    p = p.right;
                else
                    return p;
            }
        }
        return null;
    }

get方法:根据key查找元素。

get方法通过调用getEntry方法来查找容器中是否存在该元素,然后根据getEntry方法的返回结果来进行处理,如果没找到返回null,则返回null,如果找到了该元素,则返回该元素的value。

getEnry方法:根据key查找容器中是否存在该元素。

  • 首先判断构造函数时是否传入comparator的实现类,如果传入,则调用getEntryUsingComparator方法进行查找。
  • 如果没有传入,则先判断key是否为null,如果为null则抛出异常。
  • 如果以上都没有问题,则将key转换为Comparable(如果构造函数没有传入Comparator的实现类,则key必须实现Comparable接口),然后遍历树并用Comparable的compareTo方法来确定该key存在的位置。判断该元素是否存在,存在则返回该元素,否则返回null。

getEntryUsingComparator方法:调用构造函数传入的Comparator比较器来确定key在树中的位置,查找是否存在该元素。

实现逻辑和上面类似,都是遍历树,根据comparator的compareTo方法来判断key应该存在的位置,然后判断是否存在该元素,存在则返回该元素,不存在则返回null。

    public V remove(Object key) {
        Entry<K,V> p = getEntry(key);
        if (p == null)
            return null;

        V oldValue = p.value;
        deleteEntry(p);
        return oldValue;
    }

    private void deleteEntry(Entry<K,V> p) {
        modCount++;
        size--;

        // If strictly internal, copy successor's element to p and then make p
        // point to successor.
        if (p.left != null && p.right != null) {
            Entry<K,V> s = successor(p);
            p.key = s.key;
            p.value = s.value;
            p = s;
        } // p has 2 children

        // Start fixup at replacement node, if it exists.
        Entry<K,V> replacement = (p.left != null ? p.left : p.right);

        if (replacement != null) {
            // Link replacement to parent
            replacement.parent = p.parent;
            if (p.parent == null)
                root = replacement;
            else if (p == p.parent.left)
                p.parent.left  = replacement;
            else
                p.parent.right = replacement;

            // Null out links so they are OK to use by fixAfterDeletion.
            p.left = p.right = p.parent = null;

            // Fix replacement
            if (p.color == BLACK)
                fixAfterDeletion(replacement);
        } else if (p.parent == null) { // return if we are the only node.
            root = null;
        } else { //  No children. Use self as phantom replacement and unlink.
            if (p.color == BLACK)
                fixAfterDeletion(p);

            if (p.parent != null) {
                if (p == p.parent.left)
                    p.parent.left = null;
                else if (p == p.parent.right)
                    p.parent.right = null;
                p.parent = null;
            }
        }
    }

remove方法:移除key对应的元素。

  • 首先调用getEntry方法来查找该元素
  • 如果没有找到,则返回null
  • 如果找到了,则调用deleteEnry方法来删除该元素并返回删除的元素的value值。
    public int size() {
        return size;
    }

size方法:返回容器中元素的数量。

    public boolean containsKey(Object key) {
        return getEntry(key) != null;
    }

containsKye方法:判断该容器中是否含有该key。

getEntry方法之前已经介绍过了。

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

getFirstEnry方法:返回第一个元素,即红黑树的最左边的节点。

    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;
    }

containsValue方法:判断容器中是否存在该value。

从第一个值开始遍历,即从最左边的子树遍历。

总结

TreeMap是一个有序的、非线程安全、底层基于红黑树的key-value容器。

Java中实现排序的两种方式:

  • 实现Comparator接口里面的compareTo方法来定义对象的比较(外部排序,只是一个比较大小算法)
  • 要排序的实体类实现Comparable接口里面的compareTo方法(内部排序,Comparable接口相当于一个排序器,只要实现了这个接口,该类就支持排序)

TreeMap对这两种方法都支持,TreeMap实现了NavigableMap接口,该接口实现了SortedMap接口,而SortedMap里面定义了一个Comparator接口,相当于TreeMap实现了一个Comparator接口,可以通过构造函数传入指定的Comparator的实现类。TreeMap在put元素时,如果发现构造函数没有传入Comparator接口的实现类,则会将key转换成Comparable接口类型去调用compareTo方法进行key的比较,如果key也没有实现则会抛出异常。

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值