哈希-hash
一. 概念
1.引例
有线性表(1,75,324,43,1353,90,46,… )
目的:查找值为90的元素
常见做法:
1、通过一维数组进行遍历查找 (依次比较)( O(n) )
2、如果关键字有序,可采用二分查找 ( O(logn) )
缺陷:当数据规模极大的时候,查找将会变得效率低下。
假设:如果知道待查询关键字的地址,则只需要一次就可以查到。
问题:如何立刻知道关键字的地址?
Hash函数: 根据关键字直接计算出元素所在位置的函数。
例:设哈希函数为:H(K)=K/3+1,则构造关键字序列为 1、2、5、9、11、13、16、21、27 的哈希表(散列表)为:
2.哈希表
根据设定的哈希函数 H(key) 和处理冲突的方法将一组关键字映象到一个有限的连续的地址集(区间)上,并以关键字在地址集中的“象”作为记录在表中的存储位置,这种表便称为哈希表,这一映象过程称为哈希造表或散列,所得存储位置称为哈希地址或散列地址。
简单的说,哈希表可以根据一个key值来直接访问数据。其实,哈希表其实本质上就是一个数组
3.冲突
两个不同的关键字具有相同的存储位置。(多个关键字通过hash函数得到的地址是同一个地址)
在哈希存储中,若发生冲突,则必须采取特殊的方法来解决冲突问题,才能使哈希查找能顺利进行。虽然冲突不可避免,但可以减少冲突的发生,发生冲突的可能性与三个方面因素有关。
1、装填因子α
装填因子是指哈希表中己存入的元素个数 n 与哈希表的大小 m 的比值,即α=n/m。α越小,发生冲突的可能性越小,反之,发生冲突的可能性就越大。但是,α太小又会造成大量存贮空间的浪费,因此必须兼顾存储空间和冲突两个方面。
2、所构造的哈希函数
构造好的哈希函数,使冲突尽可能的少。
3、解决冲突的方法
设计有效解决冲突的方法 。
二.哈希函数的构造方法
构造哈希函数的方法很多,下面我们来列举常见的几种:
1.直接定址法
取关键字或关键字的某个线性函数值为散列地址,即H(K)=K 或 H(K)=a * K + b(其中a、b为常数)。
例:关键字集合为 { 100,300,500,700,800,900 }, 选取哈希函数为 Hash(key)=key/100,则存储结构(哈希表)如下:
优点:以关键码 key 的某个线性函数值为哈希地址,不会产生冲突。
缺点:要占用连续地址空间,空间效率低。
2.除后余数法
取关键字被不大于散列表表长 m 的数 p 除后所得的余数为哈希函数。即
H(K)=K mod p (p≤m)
ps:经验得知,一般可选p为质数 或 不包含小于20的质因子的合数。
p一般取131,1331,13331……
3. 平方取中法
取关键字平方后的中间几位为哈希函数,因为中间几位与数据的每一位都相关 举个栗子:1314的平方是1726596,那么即可取265作为它的地址
4. 数字分析法
即选用关键字的某几位组合成哈希地址,选用的这些数字应具有很高的辨识度,比如说一串数的前四位大致相同,而后四位毫无关联的话,理应优先取后四位
5.折叠法
是将关键字按要求的长度分成位数相等的几段,最后一段如不够长可以短些,然后把各段重叠在一起相加并去掉进位,以所得的和作为地址
举个例子:42751896=427+518+96=1041
6. 随机数法
选择一个随机函数,取关键字的随机函数值为它的哈希地址,即H(key)=random (key) 其中random为随机函数(random是C语言函数)。
通常,当关键字长度不等时采用此法构造哈希函数较恰当
ps:随机都是伪随机,都是通过某种算法实现的对应值,C++使用cstdlib头。文件
实际操作中需视不同情况采用不同的哈希函数。
通常考虑的因素:
(1)计算哈希函数所需时间(包括硬件指令的因素);
(2)关键字的长度;
(3)哈希表的大小;
(4)关键字的分布情况;
(5)记录的查找频率。
三.处理冲突的方法
1.开放地址法
开放地址就是表中尚未被占用的地址,当新插入的记录所选地址已被占用时,即转而寻找其它尚开放的地址。
(1)线性探测法
设散列函数 H(K) = K mod m (m为表长),若发生冲突,则沿着一个探查序列逐个探查(也就是加上一个增量),那么,第i次计算冲突的散列地址为:
Hi = (H(K)+di) mod m (di=1,2,…,m-1)
2.链地址法
基本思想:
将具有相同哈希地址的记录链成一个单链表,m个哈希地址就设 m个单链表,然后用一个数组将m个单链表的表头指针存储起来,形成一个动态的结构。
例:设{ 47, 7, 29, 11, 16, 92, 22, 8, 3, 50, 37, 89 }的哈希函数为:Hash(key)=key mod 11,用拉链法处理冲突,建表。
有冲突的元素可以插在表尾,也可以插在表头(此例为头插法)。
3.再哈希法
基本思想:
Hi= RHi(key) i=1,2,3,……,k。
其中,RHi均是不同的哈希函数,即在同义词产生地址冲突时计算另一个哈希函数地址,直到冲突不再发生。
4.建立一个公共溢出区
基本思想:
假设哈希函数的值域为[0,m-1],则设向量HashTable[0,m-1]为基本表。在此基础上,再建立一个溢出表,在之后的哈希操作中,无论关键字的同义词生成怎样的哈希地址,一旦发生冲突,就将其放入溢出表中。
Show Time
Crazy Search
兔子与兔子
Hash 键值 (hash)
本文来自博客园,作者:Doria_tt,转载请注明原文链接:https://www.cnblogs.com/pangtuan666/p/16508000.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!