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. 基于Github搭建SrpingCloudConfig详解

    最近在看SpringCloud,为了帮助自己学习和记忆,所以写下这篇文章. 从SpringCloud官方文档上看SpringCloudConfig其实为我们提供配置外部化的一个服务,可以理解成就是个w ...

  2. JAVA基础之——版本控制系统之git

    1 版本控制系统是什么 当多人协作开发一套产品时,需要能够保证代码都能够共用,那么版本控制系统就应运而生. 2 GIT 当前用的比较多的是svn和git,本文以git为例进行讲解. git诞生于200 ...

  3. java核心技术-内部类

    高级类特性-(类的成员之一:内部类) 内的成员之一:内部类(属性.方法.构造器.代码块) 可以有四种权限访问修饰符 注意:外部类 只有两种 public 和 default 定义 : 可以将一个类的定 ...

  4. Django(二):url和views

    网络通讯的本质是socket,从socket封装到MVC模式,参见另外几篇博客.本节笔记整理自Django2.0官方文档. 一.url调度器 - django.urls.path django2.0中 ...

  5. HTML颜色的三种写法

    颜色的三种写法: 1.16进制代码     #000000 2.英文字母         red 3.rgba                rgba(0-255,0,0,0-1) 例如: <b ...

  6. csharp: Gets a files formatted size.

    /* ASP.NET 默认上传文件是4M ,可以修改服务配置.. <system.web> <!-- 指示 ASP.NET 支持的最大文件上载大小. 该限制可用于防止因用户将大量文件 ...

  7. 使用匿名函数给setInterval()传递参数

    在使用JScript的时候,我们有时需要间隔的执行一个方法,比如用来产生网页UI动画特效啥的.这是我们常常会使用方法setInterval或setTimeout,但是由于这两个方法是由脚本宿主模拟出来 ...

  8. latex 图形的放置

         Next: 16.3 清除未处理的浮动图形 Up: 16. 浮动图形环境 Previous: 16.1 创建浮动图形  16.2 图形的放置 图形(figure)环境有一个可选参数项允许用户 ...

  9. Android Editable

    在android的sdk中有讲,“This is the interface for text whose content and markup can be changed (as opposed ...

  10. BAT脚本编写教程简单入门篇

    BAT脚本编写教程简单入门篇 批处理文件最常用的几个命令: echo表示显示此命令后的字符 echo on  表示在此语句后所有运行的命令都显示命令行本身 echo off 表示在此语句后所有运行的命 ...