JAVA-TreeMap源码简单分析

说到TreeMap,我们不得不提HashMap;因为他俩确实很像。具体的HashMap的相关分析可以去参考https://blog.csdn.net/zhao_xinhu/article/details/82740652

我们先来看下TreeMap和HashMap的结构对比图(左边为HashMap,右边为TreeMap)。

 从上面的结构图中我们可以清晰的看出来,两个结构确实很像,虽然很像,但是我们一眼还是能看出来有区别,TreeMap比HashMap多实现了NavigableMap接口,而NavigableMap又实现了SortedMap接口;那么这两个接口其实就是TreeMap和HashMap的区别了,TreeMap比HashMap多了NavigableMap和SortedMap的相关功能。我们去具体看下相关代码。

1、SortedMap这个名字,肯定知道这个接口是提供了排序功能,那么TreeMap肯定也是具有排序功能的,我们随后再看是如何排序的,我们先来大概看下SortedMap中都有什么具体方法:

总共也就10个左右方法,我们大概看一下,都是获取key和value的,但是具体实现也要去看TreeMap中具体是怎么实现的,这里就不具体分析了。

2、我们看下NavigableMap这个接口中的方法都有哪些:

这里方法多一些,我们单看方法名称,也是获取key、value的,但是有些可以获取比指定key小或者大的对象信息;

大概看了下TreeMap的结构,我们下来看下TreeMap的部分源码。

3.1、既然可以排序,那么我们看下他是如何进行排序的。直接看put方法

    public V put(K key, V value) {
        Entry<K,V> t = root;
        //1、 这里是初始化Map的
        if (t == null) {
            compare(key, key); // type (and possibly null) check

            root = new Entry<>(key, value, null);
            size = 1;
            modCount++;
            return null;
        }
        // 初始化Map END
        //2、 下面if else区分了是否有指定的排序规则
        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);
        }
        //if else区分了是否有指定的排序规则 END
        // 3、 将指定的值放入到map链表中
        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;
    }

我把TreeMap的put方法分成了三个部分;1、首次put,初始化;2、非首次put,比较新key和老key排序;3、根据步骤2比较的值来决定是放到链表的left还是right(也就是放到老对象的前面还是后面)

1、 初始化的时候这里不多说,但是需要提醒一点,compare(key, key)这行代码会过滤key = null的这种情况,大家可以自行看下

2、 我们拿没有指定Comparator来分析,默认排序规则

            // key不能为null
            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);

这里文字不太好描述,我们举个例子:

假如,TreeMap中已经存在一个对象了,key = "b"; value="b";我们执行put("a", "a");

执行到do while循环这里,那么 t = Entry("b", "b", null);这里的null为parent;我们(cmp = "a".compareTo("b")) < 0;也就会执行t=t.left;这时候 t就变成null了,因为left没有值do while会直接跳出了

3、 执行到第三步,我们new 了一个Entry("a", "a", parent); 这里parent为Entry("b", "b", null);将parnet.left指向新节点,也就是a插入到b的前面了

来,我们上图:

 那如果这时候插入一个Entry("c", "c")节点呢?

 这样的话,TreeMap的数据结构也比较清晰了,很明显就是一棵树嘛,跟它的名字也是匹配的。和HashMap的数组+链表还是有有区别的,TreeMap就是通过这种链表的方式构建了一颗排序树,通过每次put来compareTo来比较哪个大,哪个小进行left和reight关联的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值