由于本人最近在写一个项目,为了实现数据查找以及数据修改部分的快速操作,所以采用hash对数据进行存储,而在此过程中接触到了布谷鸟hash,觉得这个hash算法还是很有意思并且高效,所以想着进行一些记录,本系列将对基本的布谷鸟hash算法进行详细描述以及原理讲解,并在此过程中对布谷鸟hash进行并行化实现,内容相对来说较多,会通过多篇博客进行讲解如果在此过程中有同学对文章有不同理解或者有疑问的请在评论区中提出,希望本系列能够对您有所帮助🚀💕。
文章目录
- 前言
- 初识布谷鸟hash
- 布谷鸟思想
- 两个桶+两个哈希函数版本
- 总结
前言
哈希表是一种常用的数据结构,它可以快速地实现数据的存储和查找,被广泛应用于数据库、网络协议、编译器等领域。然而,传统的哈希表实现常常存在哈希冲突的问题,影响了其性能和效率。
为了解决哈希冲突的问题,布谷鸟哈希算法应运而生。布谷鸟哈希算法采用了一种高效的哈希碰撞解决方案,能够在保证高性能的同时避免哈希冲突,成为了哈希表实现领域的一个重要算法。
随着数据量的不断增加,哈希表的并发性能和处理能力越来越受到关注。因此,为了进一步提高布谷鸟哈希算法的性能和效率,需要对其进行并行化实现。
本文主要介绍布谷鸟哈希算法的基本原理和代码实现
。首先,我们将介绍布谷鸟哈希算法的原理和实现,包括哈希函数、冲突处理、布谷鸟路径等方面。然后,我们在后续将探讨如何将布谷鸟哈希算法进行并行化实现,包括并行化思路和方法、代码实现和性能测试等方面。
为了更好地阅读本文,建议读者先了解哈希表的基本概念和原理,以及并行化编程的基本知识和技巧。同时,本文的代码实现基于C++语言,读者需要具备一定的编程基础。
初识布谷鸟hash
布谷鸟哈希算法是一种哈希表实现算法,它采用了一种高效的哈希碰撞解决方案,能够在保证高性能的同时避免哈希冲突。布谷鸟哈希算法的具体实现步骤如下:
1、
初始化哈希表:首先需要初始化一个空的哈希表,包括哈希表大小、哈希函数等信息。
2、
哈希函数:选择一个合适的哈希函数,将关键字映射到哈希表的槽位中。
3、
冲突处理:当两个关键字被映射到同一个槽位时,需要进行冲突处理。布谷鸟哈希算法采用了"布谷鸟"的思想,将哈希表中的每个槽位称为"鸟巢",将关键字称为"布谷鸟"。当发生哈希冲突时,将"布谷鸟"放入其他"鸟巢"中,从而避免哈希冲突。
4、
布谷鸟路径:为了实现布谷鸟哈希算法中的"布谷鸟"移动,需要定义"布谷鸟路径"。“布谷鸟路径"是一个序列,包括多个"鸟巢”,用于存储"布谷鸟"的移动路径。当发生哈希冲突时,将"布谷鸟"移动到"布谷鸟路径"中的下一个"鸟巢"中,直到找到一个空的"鸟巢",从而解决哈希冲突。
5、
扩容处理:当哈希表的负载因子达到一定阈值时(这里一般是以“kick out
“作为标准),需要对哈希表进行扩容。扩容的过程包括创建一个新的哈希表、将旧哈希表中的数据迁移到新哈希表中、将全局哈希表指针指向新哈希表等步骤。
总之,布谷鸟哈希算法采用了一种高效的哈希碰撞解决方案,能够在保证高性能的同时避免哈希冲突。它是一种非常实用的哈希表实现算法,在数据存储和查找、哈希碰撞处理等方面都具有重要的应用价值。
布谷鸟思想
布谷鸟思想来自布谷鸟筑巢的思想,布谷鸟的行为主要是:
1、
布谷鸟妈妈从不筑巢,它将自己的鸟蛋生在其他鸟类的巢穴里,要别的鸟给它孵蛋
2、
新出生的布谷鸟会本能地将巢穴里的其他蛋踢开(kick out ),推出鸟巢,以确保自己在鸟巢里可以独享宠爱。
我们来举个例子吧:借用大佬的几张图,目前要往哈希桶中插入129、312、875以及234四个元素,并且有两个hash函数,h1(x)=x%5以及h2(x)=(x/10)%5
当我要对234进行插入时产生冲突(先使用h1进行映射,发现h1(234) = 234%5 = 4,但是bucket的四号位已经给占了)
那么接下来的流程就是:
1、将129kick out
(利用h2(x)=(x/10)%5对129进行再次计算)
发现h2(129) = 2,但是bucket的2号位也给占了,所以129踢出312,而312利用h2哈希函数进行重新计算
布谷鸟哈希的具体实现方式可以根据情况而异,可以采用不同的桶数和哈希函数数量来满足不同的需求。一般来说,布谷鸟哈希的实现方式可以分为以下几种情况:
-
一个桶+两个哈希函数:这种实现方式在处理哈希冲突时比上一种方式更加高效,因为它使用了两个哈希函数来减少冲突的可能性。当键值对哈希到同一个桶时,会使用第二个哈希函数来计算一个新的桶号,以减少冲突的可能性。
-
两个桶+两个哈希函数:这种实现方式使用了两个桶和两个哈希函数,每个桶都有一个对应的哈希函数。当键值对哈希到同一个桶时,会将它们插入到另一个桶中,以减少冲突的可能性。
-
多个桶+多个哈希函数
两个桶+两个哈希函数版本
在这分享两个桶+两个哈希函数的版本
步骤如下:
两个hash函数分别是hash1和hash2,而两个桶分别是table1和table2
1、首先使用hash1来处理key
,得到6,应该放到table1的6号位,但是发现table1的6号位有a
在,所以将key放到6号位,将a
给kick out。
2、将a
通过hash2进行重新计算,得到5,应该将a
放到table2的5号位,但是发现table2的5号位有b
在,所以将a
放到table2的5号位,将b
给kick out.
3、将b
通过hash1进行重新计算,得到2,应该将b
放到table1的2号位,由于2号位没存东西,那么就将b
给放到table1的2号位,结束插入。
总的来说呢就是,先将元素通过hash1放到table1中,如果在table1中发生冲突,就使用hash2来处理刚刚被kick out的值,将重新得到的结果放入到table2中,如果在table2中又发生冲突,那就就使用hash1来处理被kick out的值,将计算结果放入到hash1中,直到找到空位置。
这里需要提到的是,假如我们在一次插入的时候kick out元素的次数到达一定的阈值(比如是501次),但是我们在初始的时候设置的kick out 的最大次数是500次,那么这时候就需要将hash桶给进行扩容(说明冲突太多了需要调整好桶的大小),再将桶中的数据进行重新映射插入
总结
本节主要是讲解了布谷鸟hash的一些相关概念、思想以及图解,在下一篇文章中将着眼于代码实现,以及布谷鸟hash的一些变体,希望这篇文章能够对您有所帮助,如果觉得这篇文章的一些地方有问题或者有不同理解也请在评论区中提出,谢谢您嘞😊🚀🚀