Hash表(C++)

        本篇将会开始介绍有关于 unordered_map 和 unordered_set 的底层原理,其中底层实现其实就是我们的 Hash 表,本篇将会讲解两种 Hash 表,其中一种为开放定址法,另一种为 hash 桶,在unordered_map 和 unordered_set 的底层实现中主要是使用的是 hash 桶。

        本篇分别介绍了 hash 表的两种实现方法,接着讲解 hash 冲突、扩容与 hash 函数的设计原则。最后使用代码实现 hash 表的数据结构。

目录

hash概念

1. 开放定址法

2. hash 桶

hash冲突与hash函数

1. hash冲突

2. hash 函数

3. hash 表的扩容

代码实现

1. 开放定址法

2. hash 桶

hash概念

        我们在顺序结构或者平衡树中,想要查找一个数必须经过关键码的多次比较,顺序查找的时间复杂度为O(n),平衡树的查找时间复杂度为O(logn)。但是是否存在一种搜索方法,我们可以不经过任何比较,直接从表中找到我们想要的元素

        我们构建的 hash 表就可以达到这样的效果:通过某种函数(hashfunc)使元素的存储位置与它的关键码之间能够建立一一映射的关系,那么我们在查找时通过该函数可以很快的找到该元素

        构造出相应的结构:

        插入元素:根据待插入元素的关键码,以此函数计算出该元素的存储位置并按此方法进行存放。

        搜索元素:对元素的关键码进行同样的计算,把求得的函数值当做元素的存储位置,在结构中按此位置取出元素比较,若关键码相同,则搜索成功。

        本篇一共构造两种结构:开放定址法、hash 桶。如下:

1. 开放定址法

        关于开放定址法,其中的主要思想为:构建一个存放数据的 hash 表,然后通过 hashfunc 计算出元素对应的关键码,然后将元素对应的放置在相应的 hash 表中的位置,如下:

        假设我们存放元素集合:{1,7,6,4,5,9}。

        当我们想要进行搜索元素的时候,我们就可以直接使用对应的 hash 函数搜索对应的元素。

2. hash 桶

        关于 hash 桶,其主要思想为:我们首先先建立一个 hash 表,在 hash 表中的每一个位置,我们都直接将使用哈希函数计算出元素对应的关键码存放到对应位置,如下:

        假设我们存放的元素集合为:{1,7,6,4,5,9,44}。

        当其中同一个位置存在多个元素的时候,我们只需要将多的元素链接到最后元素的后面即可。

hash冲突与hash函数

1. hash冲突

        在实现 hash 表,计算元素对应的关键码的时候,难免会遇到关键码相同的情况,也就是同一个位置将会存放两个元素,也就是 hash 冲突。对于开放定址法而言就会存在 hash 冲突,而 hash 桶则不用担心会出现 hash 冲突

        关于 hash 冲突的解决方法:

        线性探测:从发生冲突的位置开始,依次向后探测、直到寻找到下一个空位置为止。如下:

        插入:首先通过哈希函数获取插入元素在哈希表中的位置,若该位置没有元素则直接插入新的元素,若该位置中有元素发生哈希冲突,我们则使用线性探测找到下一个空位置,然后在插入元素,如下:

        删除:关于使用线性探测法删除元素,我们不能直接删除元素,直接删除元素将会影响其他元素的搜索。比如删除元素4,如果直接将其删掉,44的查找将会受到影响,所以线性探测采用标记的伪删除法来删除一个元素

enum State {EMPTY, EXIST, DELETE};
// EMPTY此位置为空
// EXIST此位置存在元素
// DELETE此位置元素已经删除

        二次探测:线性探测的缺陷是产生冲突的数据会堆积在一块,这与查找下一个空位置有关系,因为找空位置的方法就是挨着往后逐个去找,因此二次探索为了避免该问题,找到下一个空位置的方法为:Hi = (H0 + i ^ 2) % m 或者 Hi = (H0 - i ^ 2) % m,其中 H0 为通过散列函数计算出的关键码对应的位置,m 是表的大小。

2. hash 函数

        关于引起 hash 冲突的一个原因为:hash 函数的设计不合理。

        关于 hash 函数的设计原则有

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值