算法——(4)哈希、hashmap、hashtable
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的更多相关文章
- [Java集合] 彻底搞懂HashMap,HashTable,ConcurrentHashMap之关联.
注: 今天看到的一篇讲hashMap,hashTable,concurrentHashMap很透彻的一篇文章, 感谢原作者的分享. 原文地址: http://blog.csdn.net/zhanger ...
- Java 集合系列14之 Map总结(HashMap, Hashtable, TreeMap, WeakHashMap等使用场景)
概要 学完了Map的全部内容,我们再回头开开Map的框架图. 本章内容包括:第1部分 Map概括第2部分 HashMap和Hashtable异同第3部分 HashMap和WeakHashMap异同 转 ...
- 杨晓峰-Java核心技术-9 HashMap Hashtable TreeMap MD
目录 第9讲 | 对比Hashtable.HashMap.TreeMap有什么不同? 典型回答 考点分析 知识扩展 Map 整体结构 有序 Map HashMap 源码分析 容量.负载因子和树化 精选 ...
- Map总结(HashMap, Hashtable, TreeMap, WeakHashMap等使用场景)
概要 学完了Map的全部内容,我们再回头开开Map的框架图. 本章内容包括:第1部分 Map概括第2部分 HashMap和Hashtable异同第3部分 HashMap和WeakHashMap异同 转 ...
- hashmap hashtable
作者:付佳豪链接:https://zhuanlan.zhihu.com/p/37607299来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 在面试的时候,java集合最 ...
- Map总结--HashMap/HashTable/TreeMap/WeakHashMap使用场景分析(转)
首先看下Map的框架图 1.Map概述 1.Map是键值对映射的抽象接口 2.AbstractMap实现了Map中绝大部分的函数接口,它减少了“Map实现类”的重复编码 3.SortedMap有序的“ ...
- 彻底搞懂HashMap,HashTable,ConcurrentHashMap之关联.
注: 今天看到的一篇讲hashMap,hashTable,concurrentHashMap很透彻的一篇文章, 感谢原作者的分享. 原文地址: http://blog.csdn.net/zhange ...
- HashMap Hashtable区别
http://blog.csdn.net/java2000_net/archive/2008/06/05/2512510.aspx 我们先看2个类的定义 public class Hashtable ...
- HashMap,HashTable,TreeMap区别和用法
开始学HashTable,HashMap和TreeMap的时候比较晕,觉得作用差不多,但是到实际运用的时候又发现有许多差别的.需要大家注意,在实际开发中以需求而定. java为数据结构中的映射定义了一 ...
- 算法:哈希表格(Hash Table)
背景 Java 和 .Net 平台都有一个所有引用类型都会间接或直接继承的类型:Object,这个类型提供最基本的相等性比较算法和哈希算法,很多书上都给出了在重写这两个算法的时候的主意事项,其中大多数 ...
随机推荐
- 撩课-Java每天5道面试题第20天
131.Spring是什么? 他解决的是业务逻辑层和其他各层的松耦合问题, 因此它将面向接口的编程思想 贯穿整个系统应用. Spring是一个轻量级的IoC和AOP容器框架. 目的是解决企业应用开发的 ...
- 撩课-Java每天10道面试题第6天
51.HashMap的实现原理 HashMap的主干是一个Entry数组. Entry是HashMap的基本组成单元, 每一个Entry包含一个key-value键值对. HashMap基于hashi ...
- 常见IT英语单词
lable标签,master精通.主人,reference参考,release发布,schema模式,component组件,persistence持久化,generate生成产生,plugin插件, ...
- 中小型研发团队架构实践三:微服务架构(MSA)
一.MSA 简介 1.1.MSA 是什么 微服务架构 MSA 是 Microservice Architect 的简称,它是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相通讯.互相 ...
- 在Ubuntu 14.04.1 LTS 上安装gettext失败
使用apt-get install -f,因为有额外的依赖.
- 浏览器根对象window之窗体和工具条
1. 窗体和工具条 1.1 窗体 frames.self.window.parent.top.opener. frames 数组类型,页面中iframe的引用,如果页面有2个iframe,则frame ...
- 【MFC】CHtmlView或WebBrowser禁止脚本错误提示
错误展示: 解决办法: 1.CHtmlView类或子类 CHtmlView::SetSilent(TRUE); 2.IWebBrowser2控件 IWebBrowser2::put_Silent(TR ...
- 【javascript】javascript设计模式之工厂模式
1.要解决的问题 2.如何实现 3.与构造函数的区别 4.总结 1.要解决的问题 工厂模式通常用于重复创建相似对象,提供动态创建对象的接口. 2.工厂模式最为设计模式中构造模式之一,通常在类或类的静态 ...
- Android学习笔记(5)----启动 Theme.Dialog 主题的Activity时程序崩溃的解决办法
新建了一个Android Studio工程,在MainActivity的主界面中添加了两个按钮,点击其中一个按钮用来启动 NormalActivity,点击另一按钮用来启动DialogActivity ...
- MySQL 常用语句大全
MySQL 常用语句大全 一.连接 MySQL 格式: mysql -h 主机地址 -u 用户名 -p 用户密码 1.例 1:连接到本机上的 MYSQL. 首先在打开 DOS 窗口,然后进入目录 my ...