Fork me on GitHub

哈希表

使用哈希表可以进行非常快速查找操作。

哈希是什么?

散列(hashing)是电脑科学中一种对资料的处理方法,通过某种特定的函数/算法(称为散列函数/算法)将要检索的项与用来检索索引(称为散列,或者散列值)关联起来,生成一种便于搜索的数据结构(称为散列表)。也译为散列。旧译哈希(误以为是人名而采用了音译)。它也常用作一种资讯安全的实作方法,由一串资料中经过散列算法(Hashing algorithms)计算出来的资料指纹(data fingerprint),经常用来识别档案与资料是否有被窜改以保证档案与资料确实是由原创者所提供。 —维基百科

哈希函数

所有的哈希函数都具有如下一个基本特性:如果两个散列值是不相同的(根据同一函数),那么这两个散列值原始输入也是不相同的。这个特性是散列函数具有确定性的结果,具有这种性质的散列函数称为单向散列函数

哈希表

名称 内容
散列表 关键字为k,则其值存放在f(k)存储位置上。由此,不需比较便可直接取得所查记录称这个对应关系f为散列函数,按这个思想建立的表为散列表
散列地址 对不同的关键字可能得到同一散列地址,即k1≠k2,而f(k1)=f(k2),这种现象称为冲突。具有相同函数值的关键字对该散列函数来说称做同义词。综上所述,根据散列函数f(k)和处理冲突的方法将一组关键字映射到一个有限的连续的地址集(区间)上,并以关键字在地址集中的“像”作为记录在表中的存储位置,这种表便称为散列表,这一映射过程称为散列造表散列,所得的存储位置散列地址
散列函数 若对于关键字集合中的任一个关键字,经散列函数映象到地址集合中任何一个地址的概率是相等的,则称此类散列函数为均匀散列函数(Uniform Hash function),这就是使关键字经过散列函数得到一个“随机的地址”,从而减少冲突

处理冲突

若两个键经hash函数处理得到相同的结果,则称此种情况为出现了冲突冲突的解决有以下几种方法。

  1. 开放定址法
  2. 单独链表法
  3. 双散列
  4. 再散列
  5. 建立一个公共溢出区

介绍一下java中使用的一种处理冲突的方法

单独链表法:将散列到同一个存储位置的所有元素保存在一个链表中。实现时,一种策略是散列表同一位置的所有冲突结果都是用存放的,新元素被插入到表的前端还是后端完全取决于怎样方便。

查找效率

  • 散列表查找过程基本上和造表过程相同。

  • 一些关键码可通过散列函数转换的地址直接找到,另一些关键码散列函数得到的地址上产生了冲突,需要按处理冲突的方法进行查找

  • 在介绍的三种处理冲突的方法中,产生冲突后的查找仍然是给定值关键码进行比较的过程,所以,对散列表查找效率的量度,依然用平均查找长度来衡量。

  • 查找过程中,关键码的比较次数,取决于产生冲突的多少,产生的冲突少,查找效率就高,产生的冲突多,查找效率就低。

  • 影响产生冲突多少的因素,也就是影响查找效率的因素。


影响产生冲突多少有以下三个因素:

  1. 散列函数是否均匀;

  2. 处理冲突的方法;

  3. 散列表载荷因子(英语:load factor)。


载荷因子

  1. 散列表的载荷因子定义为:α= 填入表中的元素个数 / 散列表的长度
  1. α是散列表装满程度的标志因子

  2. 由于表长定值,α与“填入表中的元素个数”成正比,所以,α越大,表明填入表中的元素越多产生冲突的可能性就越大;反之,α越小,表明填入表中的元素越少产生冲突的可能性就越小

  3. 实际上,散列表平均查找长度载荷因子α的函数,只是不同处理冲突的方法有不同的函数

  1. 对于开放定址法荷载因子是特别重要因素,超过0.8,查表时的CPU缓存不命中(cache missing)按照指数曲线上升。因此,一些采用开放定址法的hash库,如Java的系统库限制了荷载因子为0.75,超过此值将resize散列表