Hash算法,及HashMap使用

简介: 为什么要Hash? 哈希表是基于数组实现的,哈希算法就是如何将键值(key)转换成数组小标的方法,哈希化可以提供非常高的操作(插入、删除、查询)效率,因为对有序数组的查询,即使是二分查找也只能做到O(logN),因为哈希可以直接将要查询的key转化为数组小标,所以可以达到O(1)的时间级。 Hash算法:将key做hash后的值叫hashcode,hashcode的值范围可能很大,

为什么要Hash?

哈希表是基于数组实现的,哈希算法就是如何将键值(key)转换成数组小标的方法,哈希化可以提供非常高的操作(插入、删除、查询)效率,因为对有序数组的查询,即使是二分查找也只能做到O(logN),因为哈希可以直接将要查询的key转化为数组小标,所以可以达到O(1)的时间级。


Hash算法:将key做hash后的值叫hashcode,hashcode的值范围可能很大,Hash算法是将一个较大范围的hashcode转换为定长的区间的数值。一个好的hash算法应该使hashcode均匀分布在区间内。 但是难免还是会有不同的key会产生相同的hashcode,此为哈希冲突。

例如,要对公司100个雇员的信息做哈希存储,要求以姓名作为键值,“frank” 的hashcode是3135416,如果直接用3135416做小标,意味着要用一个非常大的数组,显然非常浪费。mod是最简单,往往也是最有效的hash算法,3135416%100=16,这样就可以用array[16]来存储“frank”的信息了。


如何解决哈希冲突?

  1. 开放定址法
    线性探测,二次探测,再哈希。
    例如“leo”的hashcode是733616,用模100哈希算法后,其值也是16,因为array[16]已经被占用了,产生了“冲突”,那么顺序查看16的下个位置17,看array[17]是否可用,如果可以则存储leo,否则继续探测下个位置18,直到有空位为止。在查询时,若一个key的哈希值为16,不能就简单的返回array[16],因为哈希值为16的可能是frank 或者 leo,所以还要比对key值。
  2. 链地址法
    Java 的 HashMap就是用LinkedList解决hash冲突的。

参考:http://en.wikipedia.org/wiki/Hash_function


使用Java HashMap时,注意以下几点:

1. HashMap不是线程安全的

不要在并发环境中使用HashMap,这样会造成不可预期的后果,据sun的说法,在扩容时,会引起链表的闭环,在get元素时,就会无限循环,后果是cpu100%。

如果Concurrent is a must,请用Map m = Collections.synchronizedMap(new HashMap(...))

2.如果数据大小是固定的,那么最好给HashMap设定一个合理的容量值

因为HashMap的默认容量是Capacity(16) * LoadFactor(0.75) = 12,如果你的HashMap是用来装载1万条数据的,那么HashMap会不断的扩容(resize),而每次扩容都会对原有数据做重新排列,非常的time-consuming,所以应该在初始化HashMap的时候用New HashMap(15000),负载因子(loadFactor)用默认的0.75就好了。

More about loadFactor:这个loadFactor有做什么用得呢? 是用来减少collision的,试想一下, 是不是越接近满载的时候,产生冲突的可能性越大呢,就像公交车上有16个座位,此时上来5个人,几乎不会出现抢位子的情况,因为很空。假如又上来10个人,那么15个人对16个座位,可能有些人觉得前面座位比较好,就会产生冲突并问候对方的父母。现在规定这个16座的公交车只允许载客12人,也就是负载因子是0.75,后面来的人用另一辆空车装载,这样就可以有效的解决冲突。

3.成为HashMap的key的条件

HashMap是用一个数组Entry[ ]来存储相应的Entry<K, V>的,所以在put(K, V)操作时,首先检查Key的hashCode,看该Entry在数组中是否已经存在,若不存在,加到数组中,否则,会再将K.equals()于现有已存在数组中得Entry的链表(linked list)中的K进行比较,若有相同的,将其替换, 若没有,将该Entry置于链表的头部。

在get( )操作是,是先查看HashCode,再比较equals,两者皆匹配的时候,才会返回Value。

所以这是为什么要作为HashMap的key要override hashCode 和 equals的原因。

参考:http://www.iteye.com/topic/754887

4. HashMap 和 HashTable, HashSet的比较

1.Hashtable是Dictionary的子类,HashMap是Map接口的一个实现类;
2.Hashtable 中的方法是同步的,而HashMap中的方法在缺省情况下是非同步的。
3.HashMap 允许key和value为null,HashTable则不允许
4. HashTable直接用对象的hashCode,HashMap有自己的hash算法
5. HashSet不是Map是Set,其与ArrayList的区别是HashSet不允许重复元素,可通过HashMap.keySet()获得HashMap中key的set

发现一个对hash深入研究的博文,以及用hash做Top K 问题的solution (有1000万条(查询串)记录,找出里面top 10出现次数最多的查询串的方法)

http://blog.csdn.net/v_july_v/article/details/6256463


目录
相关文章
|
7月前
|
索引
HashMap中hash()方法的位运算
HashMap中hash()方法的位运算
HashMap中hash()方法的位运算
|
7月前
|
存储 缓存 负载均衡
一致性 Hash 算法 Hash 环发生偏移怎么解决
一致性 Hash 算法 Hash 环发生偏移怎么解决
150 1
|
2月前
|
算法 索引
HashMap扩容时的rehash方法中(e.hash & oldCap) == 0算法推导
HashMap在扩容时,会创建一个新数组,并将旧数组中的数据迁移过去。通过(e.hash & oldCap)是否等于0,数据被巧妙地分为两类:一类保持原有索引位置,另一类索引位置增加旧数组长度。此过程确保了数据均匀分布,提高了查询效率。
45 2
|
3月前
|
存储 算法 Java
深入剖析HashMap:理解Hash、底层实现与扩容机制
【9月更文挑战第6天】在Java编程中,`HashMap`是一个常用的数据结构,其高效性和可靠性依赖于深入理解哈希、底层实现及扩容机制。哈希通过散列算法将键映射到数组索引,采用链表或红黑树处理冲突;底层实现结合数组与链表,利用2的幂次方长度加快定位;扩容机制在元素数量超过负载因子与数组长度乘积时触发,通过调整初始容量和负载因子可优化性能。
111 3
|
6月前
|
存储 算法 Java
Java查找算法概览:二分查找适用于有序数组,通过比较中间元素缩小搜索范围;哈希查找利用哈希函数快速定位,示例中使用HashMap存储键值对,支持多值关联。
【6月更文挑战第21天】Java查找算法概览:二分查找适用于有序数组,通过比较中间元素缩小搜索范围;哈希查找利用哈希函数快速定位,示例中使用HashMap存储键值对,支持多值关联。简单哈希表实现未涵盖冲突解决和删除操作。
67 1
|
5月前
|
存储 Java
Redis08命令-Hash类型,也叫散列,其中value是一个无序字典,类似于java的HashMap结构,Hash结构可以将对象中的每个字段独立存储,可以针对每字段做CRUD
Redis08命令-Hash类型,也叫散列,其中value是一个无序字典,类似于java的HashMap结构,Hash结构可以将对象中的每个字段独立存储,可以针对每字段做CRUD
|
6月前
|
算法 Java
Java中常用hash算法总结
Java中常用hash算法总结
54 0
|
7月前
|
存储 算法 Java
深入剖析HashMap:理解Hash、底层实现与扩容机制
深入剖析HashMap:理解Hash、底层实现与扩容机制
794 1
|
7月前
|
算法 数据可视化 数据处理
Algorithms_算法专项_Hash算法的原理&哈希冲突的解决办法
Algorithms_算法专项_Hash算法的原理&哈希冲突的解决办法
55 0
|
7月前
|
存储 算法 索引
Python 数据结构和算法:什么是散列表(Hash Table)?在 Python 中如何实现?
Python 数据结构和算法:什么是散列表(Hash Table)?在 Python 中如何实现?
78 0
下一篇
DataWorks