您的位置:首页 > 其它

HashMap,哈希表,哈希方法

2011-03-03 21:08 183 查看
本篇文章转载

http://www.dnbcw.com/biancheng/java/prek254784.html

http://www.javaeye.com/topic/539465

本文以自己的理解方式整理上述2篇文章,以便阅读。

hashmap的数据结构


要知道hashmap是什么,首先要搞清楚它的数据结构,在java编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的,hashmap也不例外。Hashmap实际上是一个数组和链表的结合体(在数据结构中,一般称之为“链表散列“),请看下图(横排表示数组,纵排表示数组元素【实际上是一个链表】)。



当我们往hashmap中put元素的时候,先根据key的hash值得到这个元素在数组中的位置(即下标),然后就可以把这个元素放到对应的位置中了。如果这个元素所在的位子上已经存放有其他元素了,那么在同一个位子上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。从hashmap中get元素时,首先计算key的hashcode,找到数组中对应位置的某一元素,然后通过key的equals方法在对应位置的链表中找到需要的元素。从这里我们可以想象得到,如果每个位置上的链表只有一个元素,那么hashmap的get效率将是最高的,但是理想总是美好的,现实总是有困难需要我们去克服,哈哈~

我们可以看到在hashmap中要找到某个元素,需要根据key的hash值来求得对应数组中的位置。如何计算这个位置就是hash算法。前面说过hashmap的数据结构是数组和链表的结合,所以我们当然希望这个hashmap里面的元素位置尽量的分布均匀些,尽量使得每个位置上的元素数量只有一个,那么当我们用hash算法求得这个位置的时候,马上就可以知道对应位置的元素就是我们要的,而不用再去遍历链表

哈希表与哈希方法

哈希方法在“键- 值对”的存储位置与它的键之间建立一个确定的对应函数关系 hash() ,使得每一个键与结构中的一个唯一的存储位置相对应:存储位置=hash( 键 )

在搜索时,首先对键进行hash 运算,把求得的值当做“键 - 值对”的存储位置,在结构中按照此位置取“键 - 值对”进行比较,若键相等,则表示搜索成功。

在存储“键 - 值对”的时候,依照相同的 hash 函数计算存储位置,并按此位置存放,这种方法就叫做哈希方法,也叫做散列方法。在哈希方法中使用的转换函数 hash 被称作哈希函数 ( 或者散列函数 ) 。按照此中算法构造出来的表叫做哈希表 ( 或者散列表 ) 。

Hash函数处理流程,一般翻译做"散列",也有直接音译为"哈希"的,就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,而不可能从散列值来唯一的确定输入值。简单的说就是一种将任意内容的输入转换成相同长度输出的加密方式.

哈希函数建立了从“键- 值对”到哈希表地址集合的一个映射,有了哈希函数,我们就可以根据键来确定“键 - 值对”在哈希表中的位置的地址。使用这种方法由于不必进行多次键的比较,所以其搜索速度非常快,很多系统都使用这种方法进行数据的组织和检索。

举一个例子,有一组“键值对”:

<5, ” tom ” >

<8, ” Jane ” >

<12, ” Bit ” >

<17, ” Lily ” >

<20, ” sunny ” >

我们按照如下哈希函数对键进行计算 :hash(x)=x%17+3 ,得出如下结果:

<5, ” tom ” > ----------hash(5)=8

<8, ” Jane ” >---------hash(8)=11

<12, ” Bit ” >---------- hash(12)=15

<17, ” Lily ” >----------hash(17)=3

<20, ” sunny ” >------hash(20)=6

我们把 <5, ” tom ” >、 <8, ” Jane ” >、 <12, ” Bit ” >、 <17, ” Lily ” >、 <20, ” sunny ” >分别放到地址为 8 、 11 、 15 、 3 、 6 的位置上。当要检索 17 对应的值的时候,只要首先计算 17 的哈希值为 3 ,然后到地址为 3 的地方去取数据就可以找到 17 对应的数据是“ Lily ”了,可见检索速度是非常快的。

冲突与冲突的解决

通常键的取值范围比哈希表地址集合大很多,因此有可能经过同一哈希函数的计算,把不同的键映射到了同一个地址上面,这就叫冲突。比如,有一组“键- 值对”,其键分别为 12361 、 7251 、 3309 、 30976 ,采用的哈希函数是:

public static int hash(int key){

return key%73+13420;

}

则将会得到hash(12361)=hash(7251)=hash(3309)=hash(30976)=13444 ,即不同的键通过哈希函数对应到了同一个地址,我们称这种哈希计算结果相同的不同键为同义词。

如果“键- 值 对”在加入哈希表的时候产生了冲突,就必须找另外一个地方来存放它,冲突太多会降低数据插入和搜索的效率,因此希望能找到一个不容易产生冲突的函数,即构 造一个地址分布比较均匀的哈希函数。常用的哈希函数包括:直接定址法、数字分析法、除留余数法、乘留余数法、平方取中法、折叠法等。应该根据实际工作中关 键码的特点选用适当的方法。

虽然采用合适的哈希方法能够降低冲突的概率,但是冲突仍然是不可避免的,处理冲突的最常用方法就是“桶”算法:假设哈希表有m 个地址,就将其改为 m 个“桶”,其桶号与哈希地址一一对应,每个桶都用来存放互为同义词的键,也就是如果两个不同的键用哈希函数计算得到了同一个哈希地址,就将它们放到同一个桶中,检索的时候在桶内进行顺序检索。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: