1. Hash

把任意长度的输入通过散列算法,变换成固定长度的输出,该输出就是散列值。拥有四个特性:

1. 拥有无限的输入域和固定大小的输出域

2. 如果输入值相同,返回值一样

3. 如果输入值不相同,返回值可能相同,可能不同

4. 不同输入值得到的哈希值,整体均匀的分布在输出域s中——优秀哈希函数的判断。

2. HashMap

HashMap是Node[] table哈希桶数组,其中Node是内部类,实现键值对Entry接口,并采用链表解决Hash碰撞问题。

数组默认初始长度为16,含有Loadfactor负载因子(默认为0.75),threshold=LoadFactor*length。当数组元素超过了threshold,则扩容成原来长度的两倍,并重新对map的内容进行hash,容量总是2的幂

所以保证Hash Map高效的因素是:好的hash算法使得hash值分布均匀和扩容机制。

在JDK8以后,加入了红黑树,当链表数量超过8时使用红黑树。

2.1 结构实现

HashMap是数组+链表实现。

1)是Entry键值对的数组 Node[] table,即哈希桶数组,其中Node是内部类,实现键值对Entry接口

2)HashMap就是使用哈希表来存储的,并且采用了链地址法解决冲突。

简单来说,就是数组加链表的结合。在每个数组元素上都一个链表结构,当数据被Hash后,得到数组下标,把数据放在对应下标元素的链表上。

  • 如果哈希桶数组很大,即使比较差的Hash算法也会比较分散
  • 如果哈希桶数组很小,即使很好的Hash算法也会出现较多的碰撞

所以,需要在时间成本和空间成本作出权衡,根据实际情况确定哈希桶数组的大小,并在此基础上设计好的hash算法减少Hash碰撞。——解决方式:Hash算法和扩容机制

2.2 扩容机制

  • Node[] table初始化长度length(默认16),一般为2的幂次方(主要是为了在取模和扩容时做优化,同时为了减少冲突,HashMap定位哈希桶索引位置时,也加入了高位参与运算的过程。)

    • vs HashTable:长度默认为11(素数,相对来说素数导致冲突的概率小于合数)
  • Load factor负载因子(默认是0.75)
  • threshold是Hash Map所能容纳的最大数据量的Node键值对。threshold = length*loadfactor
  • 当元素数量超过了threshold,那么就扩容resize,扩容后的容量是原来的两倍,并且重新计算每个元素在数组中的位置。

注意: 扩容是一个特别耗性能的操作,所以当程序员在使用HashMap的时候,估算map的大小,初始化的时候给一个大致的数值,避免map进行频繁的扩容。

2.3 功能实现

1. 确定哈希桶数组索引位置

Hash算法本质上就是三步:1)取key的HashCode值;2)高位运算;3)取模运算

方法一:把Hash值对数组取模运算。——时间消耗大

方法二:hash&(table.length-1)来得到该对象的保存位,当长度总是为2的幂次方时,相当于对length取模,但是&比%更高效。

在JDK1.8的实现中,优化了高位运算的算法,通过hashCode()的高16位异或低16位实现的:(h = k.hashCode()) ^ (h >>> 16),主要是从速度、功效、质量来考虑的,这么做可以在数组table的length比较小的时候,也能保证考虑到高低Bit都参与到Hash的计算中,同时不会有太大的开销。

2. HashMap的Put方法:

1. 首先根据键值key计算hash值,得到索引值i。

  • 如果table[i]=null,直接新建节点添加。并判断元素的数量是否超过threshold,
  • 如果table[i] !=null,则在该索引对应的链表中插入该元素

2. 判断数组中的元素数目是否超过thrshold,

  • 如果超过,则扩容resize成原来的两倍,并重新计算各元素的数组索引值。

此外:

(1) 负载因子是可以修改的,也可以大于1,但是建议不要轻易修改,除非情况非常特殊。

(2) HashMap是线程不安全的,不要在并发的环境中同时操作HashMap,建议使用ConcurrentHashMap。

(3) JDK1.8引入红黑树大程度优化了HashMap的性能。

https://zhuanlan.zhihu.com/p/21673805

3. 其他结构

1. HashMap

  • 根据键的hashcode值来存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序确实不确定的。
  • HashMap最多只允许一条记录的键为null,允许多条记录的值为null。
  • 非线程安全。即任一时刻可以有多个线程同时写HashMap,可能会导致数据的不一致。
  • 若要线程安全:synchronizedMap、ConcurrentHashMap

2. HashTable

是遗留类,很多映射的常用功能和Hash Map类似,不同的是它承自Dictionary类,是线程安全的。任意时刻只能有一个线程能够写HashTable,并发性不如ConcurrentHashMap,因为ConcurrentHashMap引入了分段锁。

一般不建议在新代码中使用

3. TreeMap

实现SortedMap接口,能够把它保存的记录按照键排序,默认是按键值的升序排序,也可以指定排序的比较器。在使用TreeMap时,key必须实现Comparable接口或者在构造TreeMap传入自定义的Comparator,否则会在运行时抛出java.lang.ClassCastException类型的异常。

4. LinkedHashMap

是Hash Map的一个字类,保存了记录的插入顺序,在使用Iterator遍历LinkedhashMap时,先得到的记录肯定是先插入的,也可以在构造时带参数,按照访问次序排序。

HashMap VS HashTable

1. HashMap
- Entry[] table; - size>=threshold就会扩容,threshold等于capacity*loadFactor - HashMap默认的初始容量是16,负荷系数是0.75。

扩容会对map的内容进行重新哈希,容量总是2的幂。 -

数组第一个位置放得是key=null的元素 - reHash()时: int i = indexFor(e.hash, newCapacity); 然后头插法插入新数组 -自定义对象重写equals()时也要重写hashcode();使用不可变类当key;原因都是怕存入Hashmap之后get(key)找不到元素。 - jdk1.8 链表数量超过8时改用红黑树。node<k,v>[] table;node是内部类,实现Map.Entry接口{K key; V value; node<K,V> next; int hash} - jdk1.8 扩容不需要重新计算hash,因为容量扩大两倍, 那么n-1的mask范围在高位多1bit, 只需要看看原来元素的hash值新增的那个bit是1还是0,是0的元素位置没变,是1的话索引变成“原索引+旧容量(即扩大的容量)” - jdk1.8中rehash的时候,旧链表迁移新链表的时候,如果在新表的数组索引位置相同,则链表元素bu不会倒置 - jdk1.8旧链表rehash时新建两条链表AB,如果 (e.hash&oldCap)==0是指元素位置不变,尾插法插入链表A,最后B链表插入 原索引+oldCap放到bucket里 Hashtable - Entry<K,V>{final K key; V value; Entry<K,V> next;final int hash} - 计算哈希值:int hash = hash(key.hashCode()); - 计算数组落位:hash & (capacity-1),其中capacity是2的幂 - 新增加的Entry<K,V>放在链表头部 - 扩容:使用新的容量创建新数组,将每一个元素重新计算重新落位,重新计算临界值 - 查找value必须遍历整个数组遍历每个位置上的整条链表 - Hashtable不允许键或者值是null。 - Hashtable默认数组大小11,增长old*2+1,HashMap默认数组大小16,增长2的指数。 - Hashtablehash值直接使用hashCode

算法——(4)哈希、hashmap、hashtable的更多相关文章

  1. [Java集合] 彻底搞懂HashMap,HashTable,ConcurrentHashMap之关联.

    注: 今天看到的一篇讲hashMap,hashTable,concurrentHashMap很透彻的一篇文章, 感谢原作者的分享. 原文地址: http://blog.csdn.net/zhanger ...

  2. Java 集合系列14之 Map总结(HashMap, Hashtable, TreeMap, WeakHashMap等使用场景)

    概要 学完了Map的全部内容,我们再回头开开Map的框架图. 本章内容包括:第1部分 Map概括第2部分 HashMap和Hashtable异同第3部分 HashMap和WeakHashMap异同 转 ...

  3. 杨晓峰-Java核心技术-9 HashMap Hashtable TreeMap MD

    目录 第9讲 | 对比Hashtable.HashMap.TreeMap有什么不同? 典型回答 考点分析 知识扩展 Map 整体结构 有序 Map HashMap 源码分析 容量.负载因子和树化 精选 ...

  4. Map总结(HashMap, Hashtable, TreeMap, WeakHashMap等使用场景)

    概要 学完了Map的全部内容,我们再回头开开Map的框架图. 本章内容包括:第1部分 Map概括第2部分 HashMap和Hashtable异同第3部分 HashMap和WeakHashMap异同 转 ...

  5. hashmap hashtable

    作者:付佳豪链接:https://zhuanlan.zhihu.com/p/37607299来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 在面试的时候,java集合最 ...

  6. Map总结--HashMap/HashTable/TreeMap/WeakHashMap使用场景分析(转)

    首先看下Map的框架图 1.Map概述 1.Map是键值对映射的抽象接口 2.AbstractMap实现了Map中绝大部分的函数接口,它减少了“Map实现类”的重复编码 3.SortedMap有序的“ ...

  7. 彻底搞懂HashMap,HashTable,ConcurrentHashMap之关联.

    注: 今天看到的一篇讲hashMap,hashTable,concurrentHashMap很透彻的一篇文章, 感谢原作者的分享.  原文地址: http://blog.csdn.net/zhange ...

  8. HashMap Hashtable区别

    http://blog.csdn.net/java2000_net/archive/2008/06/05/2512510.aspx 我们先看2个类的定义 public class Hashtable ...

  9. HashMap,HashTable,TreeMap区别和用法

    开始学HashTable,HashMap和TreeMap的时候比较晕,觉得作用差不多,但是到实际运用的时候又发现有许多差别的.需要大家注意,在实际开发中以需求而定. java为数据结构中的映射定义了一 ...

  10. 算法:哈希表格(Hash Table)

    背景 Java 和 .Net 平台都有一个所有引用类型都会间接或直接继承的类型:Object,这个类型提供最基本的相等性比较算法和哈希算法,很多书上都给出了在重写这两个算法的时候的主意事项,其中大多数 ...

随机推荐

  1. 03-Tomcat服务器

    一.Java分类 JavaSE Java的标准版,一般用来开发桌面应用程序, 但是在开发桌面应用程序上相对VB,Delphi,VC++并没有什么优势. JavaEE 也就是Java Enterpris ...

  2. java util 中set,List 和Map的使用

    https://www.cnblogs.com/Lxiaojiang/p/6231724.html 转载

  3. Golang的 signal

    在实际项目中我们可能有下面的需求: 1.修改了配置文件后,希望在不重启进程的情况下重新加载配置文件: 2.当用 Ctrl + C 强制关闭应用后,做一些必要的处理: 这时候就需要通过信号传递来进行处理 ...

  4. hdu 3474 Necklace 单调队列

    Necklace Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Su ...

  5. css3在页面中插入内容

    A. 使用选择器来插入内容 h2:before{ content:"前缀"; } h2:after{ content:"后缀"; } B. 指定个别的元素不进行 ...

  6. [HttpException (0x80004005): 应用程序已预编译,因此不允许使用目录“/App_Code/”。]

    删除网站下的PrecompiledApp.config文件即可.

  7. Mac系统操作指南

    OSX 采用的Unix文件系统,所有文件都挂在跟目录“ /” 下面,所以不在要有Windows 下的盘符概念.比如什么“C:”你在桌面上看到的硬盘都挂在 /Volumes 下. 比如接上个叫做“XX” ...

  8. .net core系列之《从源码对Configuration的底层运行机制进行分析》

    通过对Configuration源代码的分析从而来自定义一个配置数据源 1.用反编译工具来看看AddJsonFile()这个方法究竟干了什么,源代码如下: public static IConfigu ...

  9. Windows Server 2008 R2 /2012 修改密码策略(摘抄 原文地址 https://www.cnblogs.com/mili3/p/7799347.html)

    今天建了域环境,在添加新用户的时候,发现用简单的密码时域安全策略提示密码复杂度不够,于是我就想在域安全策略里面把密码复杂度降低一点. 问题:    在“管理工具 >> 本地安全策略 > ...

  10. linux 无法安装gcc, 可以试试换用 阿里的yum

    1.备份 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 2.下载新的CentOS-Base ...