TreeMap自定义compare后get永远返回null的问题

问题描述

今天有一个需求,需要根据map中的value进行排序,首先肯定就想到了TreeMap,于是实现了一个Comparator,代码如下:

    class ValueComparator implements Comparator<Character> {

        Map<Character, Integer> base;

        public ValueComparator(Map<Character, Integer> base) {
            this.base = base;
        }
        
        public int compare(Character a, Character b) {
            if (base.get(a) >= base.get(b)) {
                return -1;
            } else {
                return 1;
            }
        }
    }

奇怪的是,排序没有问题,可以当我使用treeMap.get()时,永远返回null。

问题跟踪

话不多说,直接debug,发现如下代码:

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

原来treeMap和hashMap的get原理完全不同,hashMap会根据key的hash值找到对应的Node获取其中的value,而treeMap在有自定义Comparator的情况下,会使用自定义Comparator将所有的key和get中的key作比较,返回值为0的时候才会返回value。
由于我自定义的Comparator只有返回1和-1,所以永远得到的都是null。

修复代码

    class ValueComparator implements Comparator<Character> {

        Map<Character, Integer> base;

        public ValueComparator(Map<Character, Integer> base) {
            this.base = base;
        }

        public int compare(Character a, Character b) {
            if (base.get(a) == base.get(b)) {
                return 0;
            } else if (base.get(a) < base.get(b)){
                return 1;
            }
            return -1;
        }
    }

其他思考

由此可见,treeMap虽时候排序,但是get的效率相较于hashMap还是较低的,毕竟hashMap可以通过key的hash值直接定位到Node的位置,不考虑hash碰撞情况下,时间复杂度是O(1)。
而treeMap则是通过compare方法,比较大小来判断是否是当前的Entry,如果返回<0,往左边找,如果返回>0,往右边找,典型的二分查找,所以时间复杂度是O(log n),所以在没有排序需求的情况下,hashMap是大家做常用的Map。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值