散列的定义与整数散列

本文介绍了散列函数的基本概念,包括直接地址法、平方取中法和除留余数法,并详细阐述了如何通过线性探测法、平方探测法和链地址法解决散列中的冲突问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一般来说,散列可以浓缩成一句话:将元素通过一个函数转化为整数,使得该整数可以尽量唯一地代表这个元素。其中,把这个转换函数称为散列函数H,也就是说,如果该元素在转换前为key,那么转换后就是一个整数H(key)

常见的散列函数有直接地址法、平方取中法、除留余数法等。其中,直接地址法是指恒等变换H(key)=key或是线性变换(即H(key)=a*key+b),而平方取中法指取key的平方的中间若干位作为hash值(很少用),一般来说比较常用的是除留余数法

除留余数法:是指把key除以一个数mod得到的余数作为hash值的方法

通过这个函数,可以把很大的数转化为不超过mod的整数,这样就可以将它作为可行的数组的下标(注意:表长TSize必须不小于mod,不然会产生越界)。显然,当mod是一个素数时,H(key)能尽可能覆盖[0,mod)范围内的每一个数。

但是稍加思考就可以注意到:通过除留余数法可能会有两个不同的数key1和key2,它们的hash值是相同的,我们把这种情况叫做冲突

解决冲突的方法:一、线性探测法、二、平方探测法;三、链地址法(拉链法),其中第一种和第二种新计算了hash值,又称为开放地址法

线性探测法

当得到key的hash值H(key),但是H(key)的位置已经被占用,那么就检查下一个位置H(key)+1是否被占用,如果没有,就使用这个位置,否则就继续检查下一个位置,hash值再加1.如果hash值超过了表长,那么就回到表的首位,继续循环,直到找到一个可用的位置或者表中的位置都已经被占用,显然,这个做法容易导致扎堆,即连续若干个位置都已经被使用过,在一定程度上会降低效率。

平方探测法

在平方探测法中,为了尽可能避免扎堆现象,当表中下标为H(key)的位置被占时,将按照下面的顺序检查表中的位置,H(key)+1^2,H(key)-1^2、H(key)+2^2,H(key)-2^2……,如果检查过程中H(key)+k^2超过了表长TSize,那么就把H(key)+k^2对表长TSize取模,如果出现H(key)-k^2小于0的情况(假设表的首位为0),那么将(H(key)-k^2)%TSize+TSize)%TSize作为结果(等价于H(key)-k^2不断加上TSize直到出现第一个非负数,如果想要避免负数的麻烦的麻烦,可以只进行正向的平方探测,可以证明,如果k在[0,Tsize)范围内无法找到位置,那么当k>=TSize时,也一定无法找到位置

链地址法

和上面两种方法不同,链地址法不计算新的hash值,而是把所有H(key)相同的key连接成一条单链表。这样可以设定一个数组Link,范围是link[0]~link[mod],其中,link[h]存放H(key)=h的一条单链表,于是当多个关键字key的hash值都是h时,就可以把这些冲突的key用单链表连接起来,此时就可以遍历这条单链表来寻找H(key)=h的key值。

当然,一般来说,可以使用标准库中的map来直接使用hash的功能,(C++11以后可以用unordered_map,速度更快),因此除非必须模拟这些方法或是对算法的效率要求比较高,一般不需要自己实现上面解决冲突的方法

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值