深入哈希表(三)--拉链法(哈希桶)实现哈希表

一、简介

为了解决线性探构造哈希表所出现的大量哈希冲突,我们采用了另外一种方法,便是开链法。而在SGI版本的STL中调用的也正是哈希桶的实现方法。

注意:

开链法实现哈希表的时候会出现很多很多的错误,比如各种模板错误,此时需要耐心,慢慢调整。同时又为了扩展hash_map与hash_set更改了一些模板参数,所以经过调试错误的过程,绝对会对模板有一个全新的认识。

二、拉链法实现原理:

采用了由N个头指针构成的数组,在每个表格内部维护一个List,经过哈希函数的计算,我们可以得到某一个List,我们所做的插入删除和查找等操作全部位于这个LIst上。

我们需要注意的是虽然List的遍历是线性的,但是如果List足够短,我们操作起来速度还是很快。

这里写图片描述

三、拉链法优缺点

优点:

  1. 解决了线性探测所导致的太多的哈希冲突。
  2. 删除结点相比于开放定址法更容易实现(在线性探测中如果删除结点,后面的结点无法访问)。
  3. 搜索的时间下降

缺点:

  1. 如果相同元素过多,元素在一个桶内部链接过长,反而导致时间复杂度上升。解决思路是桶中元素不再指向链表,而指向一个红黑树

四、拉链法实现

哈希表里面存放一个链表的指针,和一个判断的数据。可以把哈希表中的元素看作链表的第一个结点,类似于指针数组。

链表里面包含指向下一个结点的指针,数据tata,结点构造如下:

template <class ValueType>
struct HashNode
{
   
    ValueType _valueField;

    HashNode* _next;

    HashNode(const ValueType& valueField)
        :_valueField(valueField)
        , _next(NULL)
    {}
};

hashtable数据结构

插入

第一步:检查容量是否需要扩容。
第二步:查看此时的key所对应的哈希桶位置。
第三步:构造出新的结点。
第四步:找到此哈希桶位置所链接的List所对应的结点,如果存在则插入失败,不存在则插入,此时采用头插法(头插只需要考虑结点为空和不为空,但是可以直接处理)。

查找

第一步:找到此key所对应的哈希桶的位置。
第二步:进入此哈希桶所指向的List查看Key是否相同即可。

删除

类似链表删除,定义两个指针,指向前后两个元素。

第一步:找到key所对应的哈希桶的位置。
第二步:定义两个指针,一个是需要删除的指针,一个是它前一个指针。
判断两种情况

  • 情况一:要删除结点为链表的头结点
  • 情况二:删除结点为其他结点。

第三步:分以上两个结点的情况删除即可。

负载因子判别

size如果等于——table的size,增容时也可以选择重新哈希结点来构造新的哈希表,但是这样做时间复杂度很高,所以我们采用现代的写法。

现代写法是:

  1. 创建新表,resize获取容量
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值