• TreeMap的源码学习


    TreeMap的源码学习

    一)、TreeMap的特点

    根据key值进行排序。

    二)、按key值排序的两种排序算法实现

    1).在构造方法中传入比较器

    public TreeMap(Comparator<? super K> comparator) {
            this.comparator = comparator;
        }
    
       比较器comparator实现Comparator接口,实现compare(T o1, T o2)方法;
    
    int compare(T o1, T o2);
    

    2).key值实现Comparable接口,重写 compareTo(key k)方法

    T implements Comparable<T>{
        @override
        public int compareTo(T k)
    }
    

    注: 对于TreeMap而言,排序是一个必须进行的过程,要正常使用TreeMap必须制 定排序规则,加入Comparator或key对象实现Comparable接口,若没有制定 比较规则则会抛出java.lang.ClassCastException。

    因为String对象默认实现了Comparable接口,实现了comparaTo方法,使用String类型作为key值,不用进行排序。

    三)、TreeMap的数据结构

    红黑树:Entry<k, v>

    Entry<k ,v> 对象的属性:

    K key;
    V value;
    Entry<k, v> left;
    Entry<k, v> right;
    Entry<k, v> parent;
    boolean color = BLACK;
    

    红黑树是一种平衡查找树.

    四)、TreeMap的主要属性

    //比较器
    private final Comparator<? super K> comparator;
    //树的根节点
    private transient Entry<K,V> root;
    //节点个数即元素个数
    private transient int size = 0;
    //修改次数
    private transient int modCount = 0;
    //用于构造红黑树
    private static final boolean RED   = false;
    private static final boolean BLACK = true;
    

    五)、TreeMap的put(K key, V value)方法

    步骤:

    1).获取root节点,判断是否第一次添加元素 ,若是第一次添加元素则将该元素设为根节点。

    2).如若不是第一次添加,根据key值,调用比较规则从根节点开始比较左右子树直至到达叶子节点,根据key的比较结果决定放置到叶子节点的左树位置或右树位置,> 0放置右树, < 0 放置右树。

    3).fixAfterInsertion修改插入元素后树的结构,转为红黑树。

       TreeMap<String, String> treeMap = new TreeMap<>();
            treeMap.put("a","v");
    
    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);
            }
           //使用key 实现Comparable的compareTo()规则
            else {
                if (key == null)
                    throw new NullPointerException();
                @SuppressWarnings("unchecked")
                    /**
                      如果Key没有加入比较器或没有实现Comparable这里就
                      抛出java.lang,ClassCastException
                      */
                    Comparable<? super K> k = (Comparable<? super K>) key;
                //一直比较左右子树的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);
            //< 0 作为节点的左子树
           if (cmp < 0)
                parent.left = e;
            // > 0 作为节点的右子树
            else
                parent.right = e;
            //调整插入元素的树结构,转为红黑树
            fixAfterInsertion(e);
            size++;
            modCount++;
            return null;
        }
    

    六)、TreeMap的get(K key)方法

    步骤:

    1).获取根节点

    2).从根节点开始比较左右子树的key值

    3).若树中某一节点的key值与查找的key值相等,则返回对应的Entry<k, v>对象

    treeMap.get("a");
    
    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")
            //没有比较器使用comparale的compareTo()规则
                Comparable<? super K> k = (Comparable<? super K>) key;
            Entry<K,V> p = root;
            //从根节点遍历左右子树,若key值相等,则返回当前节点对象
            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;
        }
    

    注:TreeMap的功能比HashMap的功能强大, 实现了sortedMap接口,可以对元素 进行排序,单TreeMap的性能却略低于HashMap,当需要对集合进行排序操作可使用TreeMap.

    金麟岂能忍一世平凡 飞上了青天 天下还依然
  • 相关阅读:
    numpy数组(一)
    Iterator和Iterable区别:
    jupyter notebook安装相关问题
    Selenium+Headless Firefox配置
    最长不重复子串
    deprecated conversion from string constant to 'char*
    c++求字符串
    原型模式(Prototype)
    工厂方法模式(Factory Method)
    素数序列的生成及其应用(采用了自研的高效算法)
  • 原文地址:https://www.cnblogs.com/Auge/p/11660467.html
Copyright © 2020-2023  润新知