HashMap整数排序问题,Hashmap遍历速度问题,HashMap如何保证初始化长度为2的次幂

发现问题

今天算法同事问我HashMap会对整数key进行排序么?我脱口而出不能啊,结果他给我看结果,发现真的排序了,于是我自己试了一下,

    Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        map.put(3,3);
        map.put(1,1);
        map.put(5,5);
        map.put(11,11);
        map.put(6,6);
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
        }

结果如下:
在这里插入图片描述
真的排序了,于是上网搜了一下原因

问题原因

Java中的HashMap底层是用数组加链表实现的,在链表长度大于8的时候转为红黑树
而且HashMap是无序的,输出顺序不能保证为输入顺序,遍历HashMap中key的时候,都是先遍历数组下标为0的那一个链表或者红黑树,然后第二列。。。。

HashMap其实也是有序的,一组相同的key-value对,无论他们插入的顺序是什么样的,遍历时,顺序都是一致的(不改变其默认初始化容量的前提下)。

键值对插入HashMap底层数组的下标 = (数组长度-1)&key的hash值(因为数组长度都是2的次方,因此这相当与hash值对数组长度取余)

了解这个以后,发现如果输入key为17的时候,与数组长度(默认16)取余为1,会在第一列,这样就会导致HashMap的遍历顺序出问题(不扩容情况下)。

  Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        map.put(3,3);
        map.put(17,17);
        map.put(5,5);
        map.put(11,11);
        map.put(6,6);
        map.put(1,1);
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
        }

结果如下,如设想的那样
在这里插入图片描述

结论

当所有key的hash的最大值<数组的长度-1 且 个数小于HashMap初始化大小*0.75时,HashMap可以将存入的元素按照key的hash从小到大排序

Hashmap遍历速度

entrySet最快,因为使用keyset时,它使用get(key)来获得value值,因此需要遍历两次map。

HashMap如何保证初始化长度为2的次幂

为了保证HashMap中大量使用的位运算提升速度(例如使用与运算来求余),必须保证容量为2的次幂,
HashMap中有个方法,主要功能是返回一个比给定整数大且最接近的2的幂次方整数,如给定10,返回2的4次方16.

static final int tableSizeFor(int cap) {
        int n = cap - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }

我们假定n为00…1XXXX(二进制,1为第一个出现1的位置,后面随便)
n |= n >>> 1:表明n与n无符号右移一位后的或运算,表明第一个出现1的位置的下一位也变成了1!以此类推,后2位,后4位,后8位,后16位都为1,也就是第一个出现1的位置后面全是1!也就是找到了大于n的最小2的次幂-1!而1+2+4+8+16=31,可以覆盖全部的32位整形,为什么最开始要减一呢?如果n=8,经过上面一系列操作后会变为15,而减一为7就会找到最合适的8。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值