深入哈希表(二)--开放定址法实现哈希表

在上一篇文章中,我们主要是简介了哈希表,下文我们来实现开放定址法的哈希表。
开放定址法主要有两种方法,一种是线性探测,一种是二次探测,本文主要针对这两种方法进行介绍。

开放定址法–闭散列方法

一、线性探测

(1)线性探测是什么

设给出一组元素,它们的关键码为:37,25,14,36,49,68,57,11,散列表为HT[12],表的大小m = 12,假设采用Hash(x) = x % p; // (p = 11) 11是接近m的质数,就有:

Hash(37) = 4、Hash(25) = 3 、Hash(14) = 3、Hash(36) = 3、Hash(49) = 5 、Hash(68) = 2、 Hash(57) = 2、Hash(11) = 0

采用线性探查法处理冲突

这里写图片描述

如果需要加入一个元素时,使用散列函数进行计算,确定元素的桶号H0,按此桶号查看该桶,如果是所 要搜索的元素的关键码,则说明表中已有此元素,不再进行此元素的插入,否则即为冲突,再查看紧 随其后的下一个桶,如果是空桶,则搜索失败,新元素插入即可。

所以线性探测会导致一片位置冲突,在一片范围内冲突越来越多,从而导致堆积问题。

(2)线性探测的实现:

①底层

实现方法用vector作为容器,但是删除元素会变得很麻烦,这时不敢说遇到空位置就结束,因为此时查找元素是完全查找,所以我们可以给每个位置都有一个状态,状态有一为空,二存在,三删除,遇到删除不停止,遇到空可以停止。

定义为模板写成hashnode,枚举出三个状态,包含了状态和key、value,
保持size和capcity一样大。

②扩容

线性探测的扩容:
负载因子可以看作数据的占用率,一定是小于1,但是不可能为1,所以我们需要考虑的是控制负载因子,用容量除以hash的size,可以把上面的数据乘0,大于7(也可以强制转化),这时需要扩容。

但是hash的增容代价很大,不能像vector一样构造复制删除,要重新哈希,映射到新的空间中。

方法:定义新的hashtable 表,resize新的空间(获取质数表中的元素),循环对每个成员调用插入函数(此时不会增容,因为前面已经resize过了),最后转换其中的tables即可。

③插入

首先映射出index位置,此时可以包装成另外一个函数。
用另外一个函数,初步是用key%_tables的size,但是我们发现无法对string或者结构体进行取模。

我们的解决方法如下:

  • 方法一:字符串哈希算法–字符串转换为整形,
  • 方法二:可以写一个仿函数,全部强传为int,返回size_t。缺省作为参数,在函数体内部定义一个仿函数对象,传入key即可,但是需要对string类型进行单独处理,单独写string的仿函数返回字符串哈希算法,最后测试时候显示传string的模板参数即可。如果是结构体尽量去选其中的一项作为可以取模的参数。
  • 方法三:采用特化
    用循环找一个位置,删除标记和空的时候可插入, 如果值相等则不插入,判断如果出范围,定位为0。
④查找

查找和插入内部实现类似。
遇到空停止,判断如果存在并且状态为存在则找到,状态不是存在则没有找到,没有找到则向后移动,最后判断是否到底部,index再次置为0。

⑤删除

首先调用查找函数,查找状态为存在则删除(注意此时采用的是置状态为删除,这便是伪删除),–size,没有找到返回失败。

⑥hashfunc实现

主要采用仿函数,通常能变成整数的元素采用最普通的版本,本文针对于我们用的最多的string进行了一个特化版本。

不用写析构函数会自己析构。
拷贝构造也是vector内部做的。

#include <vect
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值