zoukankan      html  css  js  c++  java
  • 面试题:HashMap 容量为2次幂的原因

    HashMap构造方法还可以指定集合的初始化容量大小:

    HashMap(int initialCapacity) 构造一个带指定初始容量和默认加载因子 (0.75) 的空 HashMap。
    

    根据上述讲解我们已经知道,当向HashMap中添加一个元素的时候,需要根据key的hash值,去确定其在数组中的具体位置。 HashMap为了存取高效,要尽量较少碰撞,就是要尽量把数据分配均匀,每个链表长度大致相同,这个实现就在把数据存到哪个链表中的算法。

    这个算法实际就是取模,hash%length,计算机中直接求余效率不如位移运算(这点上述已经讲解)。所以源码中做了优化,使用 hash&(length-1),而实际上hash%length等于hash&(length-1)的前提是length是2的n次幂。

    为什么这样能均匀分布减少碰撞呢?2的n次方实际就是1后面n个0,2的n次方-1 实际就是n个1;

    举例:

    说明:按位与运算:相同的二进制数位上,都是1的时候,结果为1,否则为零。

    例如长度为8时候,3&(8-1)=3  2&(8-1)=2 ,不同位置上,不碰撞;
    例如长度length为8时候,8是2的3次幂。二进制是:1000
    length-1 二进制运算:
    	1000
    -	   1
    ---------------------
         111
    如下所示:
    hash&(length-1)
    3   &(8    - 1)=3  
    	00000011  3 hash
    &   00000111  7 length-1
    ---------------------
    	00000011-----》3 数组下标
    	
    hash&(length-1)
    2 &  (8 -    1) = 2  
    	00000010  2 hash
    &   00000111  7 length-1
    ---------------------
    	00000010-----》2  数组下标
    说明:上述计算结果是不同位置上,不碰撞;
    
    例如长度为9时候,3&(9-1)=0  2&(9-1)=0 ,都在0上,碰撞了;
    例如长度length为9时候,9不是2的n次幂。二进制是:00001001
    length-1 二进制运算:
    	1001
    -	   1
    ---------------------
        1000
    如下所示:
    hash&(length-1)
    3   &(9    - 1)=0  
    	00000011  3 hash
    &   00001000  8 length-1 
    ---------------------
    	00000000-----》0  数组下标
    	
    hash&(length-1)
    2 &  (9 -    1) = 2  
    	00000010 2 hash
    &   00001000 8 length-1 
    ---------------------
    	00000000-----》0  数组下标
    说明:上述计算结果都在0上,碰撞了;
    

    注意: 当然如果不考虑效率直接求余即可(就不需要要求长度必须是2的n次方了)

    小结:

    ​ 1.由上面可以看出,当我们根据key的hash确定其在数组的位置时,如果n为2的幂次方,可以保证数据的均匀插入,如果n不是2的幂次方,可能数组的一些位置永远不会插入数据,浪费数组的空间,加大hash冲突。

    ​ 2.另一方面,一般我们可能会想通过 % 求余来确定位置,这样也可以,只不过性能不如 & 运算。而且当n是2的幂次方时:hash & (length - 1) == hash % length

    ​ 3.因此,HashMap 容量为2次幂的原因,就是为了数据的的均匀分布,减少hash冲突,毕竟hash冲突越大,代表数组中一个链的长度越大,这样的话会降低hashmap的性能

  • 相关阅读:
    重写System.IO.MemoryStream类, 实现LumiSoft.Net.POP3.Client单封邮件的下载进度显示
    获取页面来源URL ,源页面URL,Request.UrlReferrer为空的问题
    JavaScript BOM 随笔谈
    Android 端 博客园闪存——alpha版
    除余取模的算术变化特点,模的变化特点
    EF Code First 更新部分字段时 未更新字段的验证问题
    Android 端闪存 应用——alpha 2.0 版
    简化C#版Junit
    利用 Vs2012 编译MSOpenTech/Redis ——以服务方式运行Redis
    Android requires compiler compliance level 5.0. Please fix project properties.错误
  • 原文地址:https://www.cnblogs.com/dalianpai/p/14295818.html
Copyright © 2011-2022 走看看