哈希表初探


  哈希表主要是提供常数时间的基本操作。它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。在哈希表中,散列函数实现地址映射,但是由于存在冲突问题,所以,又必须考虑散列冲突的处理。
  散列函数:负责将某一元素映射为“大小可接受之索引”,这样的函数称为散列函数。

在这里插入图片描述

散列函数的构造方法

  如上图所示,散列函数的构造方法较多,下面就几种有代表性的进行总结。

直接定址法

  直接定址法的散列函数符合如下形式:
f ( k e y ) = a ∗ k e y + b ; f(key) = a*key + b; f(key)=akey+b;
  其中,a、b均为常数。最常见的直接定址法是数组。
  优点:简单、均匀、无冲突。
  应用场景:需要事先知道关键字的分布情况,适合查找表较小且连续的情况。例如数组就可以视作一个直接定址法的例子,其a = 1,b = 1.

除法散列法

f ( k e y ) = k / p ( p < = m ) f(key) = k/p (p <= m) f(key)=k/p(p<=m)
  由于只需要做一次除法操作,所以除法散列法是非常快的;但是如果p的取值不好,那么可能导致不同元素映射到同一个表中。

平方取中法

  将数字平方,然后再取中间三位作为散列地址,再比如关键字是 1234 那么它的平方就是 1522756 ,抽取中间 3 位就是 227 用作散列地址。

处理散列冲突

  使用散列函数可能带来问题是:不同元素被映射到相同的位置。这无法避免,这就是碰撞问题。主要有以下几种方式进行解决。

线性探测

  负载系数:元素个数除以表格大小。负载系数永远在0~1之间,如果大于1,说明元素太多,表格已经存储不下了。
  当散列函数计算元素的插入位置,而该位置上的空间已不再可用,那么就往下寻找,直到找到一个可用空间为止。
  进行元素搜索时,如果计算出来的位置上元素于我们的搜寻目标不符,那么就往下寻找,直到找到吻合者,或者遇上空格元素。
  元素删除,采用惰性删除,也就是只标记删除记号,实际删除则等待表格重新整理时再进行,这是因为哈希表中每一个元素都关系到其他元素排列。
  线性探测存在一个问题:平均插入成本的成长幅度,远高于复杂系数的成长幅度。
  线性探测法的公式如下:
在这里插入图片描述

  简单的说,就是f(key) mod m,结果产生碰撞,那么我们使用(f(key) + di) mod m,其中di是一个常数,我们使用这种方式,直到找到一个不会冲突的地址为止。

二次探测

  二次探测解决碰撞问题的方程式为:F(i) = i2
  如果散列函数计算出来新元素的位置为 H,而该位置已被使用,那么就依次尝试 H+12、H+22…。
  二次探测的公式如下:
在这里插入图片描述

  我们可以发现,二次探测与线性探测十分类似,唯一区别在于其使用的di是平方数,这种方式可以避免关键字集中在同一区域。

开链

  每一个表格元素维护一个 list:散列函数为我们分配一个 list,然后我们在那个 list 身上执行元素的插入、搜寻、删除等操作,虽然针对 list 进行的搜寻是一种线性操作,但是如果 list 够短,那么速度还是够快。
  那么开链如果碰到地址冲突会怎么样呢?开链是这样处理的,如果发现key不同而f(key)相同,那么只需要在同一子链表中添加一个节点即可。
在这里插入图片描述

  链地址法虽然能不产生冲突,但是也带来了查找时需要遍历单链表的性能消耗。

  参考博客:https://blog.csdn.net/csdnnews/article/details/110944316
  代码链接:https://github.com/KevinCoders/MyStudy/blob/master/datastructure/hashtable.cpp

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值