• HashMap


    title: HashMap
    date: 2015-09-06 19:45:38
    tags: [java,algorithm]
    categories: java

    Java最基本的数据结构有数组和链表。
    数组的特点是空间连续(大小固定)、寻址迅速,但是插入和删除时需要移动元素,所以查询快,增加删除慢。
    链表恰好相反,可动态增加或减少空间以适应新增和删除元素,但查找时只能顺着一个个节点查找,所以增加删除快,查找慢。
    那么问题来了,有没有一种综合数组和链表优点的数据结构呢?

    The answer is HashMap!

    HashMap

    首先看看HashMap是怎么个存储方式,下图无明确作者,在此不添加Reference了! 尊重原创!

    如图,hash表就是由数据+链表组成的。首先数组每个元素存储一个链表节点,通过一定算法,比如hash(key)%length
    来存储后续的节点,比如31%16=15,就放到元素15开头的链表中。


    看了HashMap的源码,其实HashMap是基于一个线性的数组结构来实现的:
    o n e: HashMap内部定义了一个Entry<k,v>数组
    t w o: static class Entry<k,v> implements Map<k,v>,并且具有key/value/next等属性,类似JavaBean
    three: 也就是,Entry[]数据存储了Map<k,v>这种结构的数据


    分析一段源码,来自HashMap中的put()方法:

      public V put(K key, V value) {
              if (key == null)
                  return putForNullKey(value);
              int hash = hash(key.hashCode());
              int i = indexFor(hash, table.length);
              for (Entry<K,V> e = table[i]; e != null; e = e.next) {
                  Object k;
                  if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                      V oldValue = e.value;
                      e.value = value;
                      e.recordAccess(this);
                      return oldValue;
                 }
              } 
            modCount++; 
            addEntry(hash, key, value, i);
            return null;
        }	
    

    其实思路并不复杂,通过一个hash算法得到hash值,通过hash值得到Entry数组下标index,然后找到数组位置,通过链式结构匹配Key值,get it!
    那么,问题在这,这是源码里的hash算法:
    static int hash(int h) { h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); }
    我真是惊呆了,费脑筋~
    虽然能猜出来其作用,大体大概是防止hash冲突,但是具体为什么这样,而不是那样,我解释不清楚了=。=!
    计算index的方法,倒是很清新,用到了效率最高的位运算,其中length-1防止数组越界:
    static int indexFor(int h, int length) { return h & (length-1); }


    另,解决hash冲突的方法:

    1. 开放定址法(线性探测再散列,二次探测再散列,伪随机探测再散列)
    2. 再哈希法
    3. 链地址法
    4. 建立一个公共溢出区

    显然HashMap采用的是链地址法


    EOF



    I am a slow walker, but I never walk backwards.



  • 相关阅读:
    【更新】Java发送邮件:个人邮箱(QQ & 网易163)+企业邮箱+Android
    git pull 出现 WARNING: POSSIBLE DNS SPOOFING DETECTED!
    Redis解决“重试次数”场景的实现思路
    IDEA更改JavaScript版本
    npm与yarn命令
    SpringBoot+Vue前后端分离项目,maven package自动打包整合
    Vue(九)使用Ant Design入门——环境搭建
    Git常用命令
    Vue(八)全局变量和全局方法
    笔记本电池怎样使用问题
  • 原文地址:https://www.cnblogs.com/lknny/p/4805231.html
Copyright © 2020-2023  润新知