教你从零开始写一个哈希表--附录

附录:其他的冲突处理方案

常见的两种哈希冲突解决方案如下:

  • 链表法
  • 开放寻址法

链表法

  分离链表法中,每一个桶包含一个链接表。当键值对的键冲突时,键值对会被加入到这个列表中。它支持的方法如下:

插入:
  计算关键字的哈希值来查找桶的下表索引。如果访问的桶没有值,把键值对插入到这个桶中。如果已经保存了键值对了,将待插入的键值对追加到链接表后面。
搜索:
  计算关键字的哈希值来查找桶的下表索引。遍历链接表,用待查找的关键字跟比较每一个键值对的关键字。如果找到了关键字,返回对应的值,否则返回空。
删除:
  计算关键字的哈希值来查找桶的下表索引。遍历链接表,用待查找的关键字跟比较每一个键值对的关键字。如果找到了关键字,从链接表中删除对应的键值对。如果链接表中只有一个键值对了,在桶中放一个空值以标志链接表是空的。

  这个方法的优势是易于实现,但是空间效率低下。每一个键值对都保存了所在链接表中的下一个节点的指针。如果没有下一个节点保存空指针。空间浪费在了记录指针上面,这本可以用来存储更多键值对的。

开放寻址法

  开放寻址法解决了链表法的空间效率低的问题。当发生冲突时,冲突的键值对被放在哈希表的其他桶中。放置键值对的桶,是依据预设好的规则来选择的。这样,查找键值对的时候可能出现重复。目前有三种常见的方法来为冲突的键值对选择选择可插入的桶。

线性探测

  当发生冲突时,增加下标,然后把键值对放在数组的下一个可用的桶中。方法如下:

插入:
  计算关键字的哈希值来查找桶的下标索引。如果桶是空的,把键值对插入的这里。如果桶是非空的,重复增加下表的动作,直到找到空的桶,然后把键值对插入到这个桶中。
搜索:
  计算关键字的哈希值来查找桶的下表索引。重复增加下标,比较每一个键值对的关键字跟待查找的关键字,直到找到一个空的桶。如果匹配到了待查询的关键字,返回对应的值,否则返回空。
删除:
  计算关键字的哈希值来查找桶的下表索引。重复增加下标,比较每一个键值对的关键字跟待删除的关键字,直到找到一个空的桶。如果匹配到了待查询的关键字,删除对应的键值对。删除一个键值对会使链表断开,我们只能把待删除的键值对后面的所有节点插入到链表的后面。

  线性探查提供了很好的缓存性能,但是导致了扩展性的问题。把冲突的键值对放在下一个可用的桶中,这可能会导致以填充的桶的连续扩张。插入、搜索或删除时,这种做法都需要遍历。

二次探测

  类似于线性探查,但它并没有把冲突的项放到下一个可用的桶中,而是尝试着放进下标为i, i + 1, i + 4, i + 9, i + 16, ...,序列的桶中。此处的i是原先的关键字哈希值。支持的方法如下:

插入:
  计算关键字的哈希值来查找桶的下表索引。遍历探查序列,直到发现了空的或者已被删除的桶,随之将键值对插入找到的桶中。
搜索:
  计算关键字的哈希值来查找桶的下表索引。遍历探查序列,直到发现了空的或者已被删除的桶,否则比较序列对应的桶中键值对的关键字和待查找的关键字;如果关键字匹配,返回对应的值,反之返回空。
删除:
  我们无法辨别待删除的项是否处于冲突链表中,因此无法立刻删除该项。我们只能将其标记为“已删除”。

  尽管二次探查法没有根除键值对的聚集,但是情况有所缓解;同时它也提高了存储的性能。

再哈希法

  再哈希法是要解决键值对聚集问题的。为此,我们使用备用哈希函数来为键值对计算新的索引位置。使用哈希函数给出新的桶,桶的下标得是全局均匀分布的。这个方法解决键值对聚集问题,同时也增强了存储的性能。再哈希法是生产中常见的冲突解决方法。教程中也实现了这个方法。

上一篇:教你从零开始写一个哈希表–调整大小

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值