简单了解一下哈希表(C++)

哈希表(Hash Table),又称散列表(从译名上看,有散乱排序的意思),是一种根据关键码值(Key)直接访问记录的数据结构。它通过哈希函数将关键码映射到表中的存储位置,实现快速查找、插入和删除操作,理想情况下时间复杂度接近 O(1)

哈希表的哈希函数(将数据元素的关键键值映射为元素存储位置的函数)有很多种,这里只讲一下 直接定址法 和 除法散列法(除留余数法)

直接定址法:

当关键字的范围比较集中时,就可以直接使用关键字的值作为存储位置的下标,比如集中在 [0,99] 范围内的,就可以开辟一个大小为100的数组,每个关键字的值就是数组下标;又或者使用关键字的某个线性函数值作为哈希地址,即通过公式 H(key)=key 或 H(key)=a×key+b(a、b 为常数)建立关键字与存储位置的一一对应关系,从而实现根据关键字直接计算存储位置。

需要注意的是,直接定址法具有局限性:它只适用于范围集中 的 整型

除法散列法(除留余数法):

除法散列法又叫除留余数法,就是用关键字 % 上哈希表大小 得到的值(余数),用来映射到开辟的空间

不管是用哪种哈希函数,都会有多个值对一个位置的情况,叫做 哈希冲突/哈希碰撞

要注意的是,哈希冲突是不可避免的,所以只能去寻找好的哈希构造方法来减少冲突的次数

当使用除留余数法时,要避免哈希表的大小为 2的幂或者10的幂 等,因为 % 可以去掉能整除的,留下不能被整除的

这里以 10的幂为例,12002和3456002 两个值如果都 % 上1000,就都只会留下002,计算出来的哈希值相同,会发生哈希冲突

所以最好不要用2的幂、10的幂,这只让部分位参与运算

让32个位都参与运算,得到的结果才是更均匀的

建议取不太接近2的整数次幂的一个质数

所以除留余数法它是对哈希表大小M是有要求的

处理冲突

既然哈希冲突避免不了,就要想办法处理哈希冲突

处理哈希冲突的主要方式有四种:开放地址法、链地址法、再哈希法和建立公共溢出区

这里讲一下 开放地址法和链地址法

开放定址法

开放地址法形成的哈希表叫做闭散列哈希表

原理:当发生哈希冲突时,会按照某种规则找到一个没有存储数据的位置进行存储

有三种不同的开放定址法,分别叫做 线性探测、二次探测、双重探测

这里只讲一下其中的线性探测

线性探测

从发生冲突的位置开始,依次线性往后探寻,直到找到某一个没有存储数据的位置为止,如果探测到了哈希表尾,就返回哈希头部继续寻找

需要注意,线性探测会出现连续冲突的问题,因为冲突数据会放到其它位置,下一个数据如果就指向这个位置,就也需要往后寻找位置

负载因子

在开放定址里,负载因子就是数组槽的占有率,在链定址法里,负载因子就是平均每个链表的长度(元素总数除以桶的个数)

负载因子越大,哈希冲突的概率越高,空间利用率越高;负载因子越小,哈希冲突的概率越低,空间利用率越低

开放定址法会控制 负载因子 在1以下,所以不会出现找不到空间存放数据的情况

底层实现

哈希表底层使用的数组,数组类型是个结构体,结构体里面有着要存的值和当前状态,状态可以帮助查找元素过程中不会受到 被删掉的元素的干扰,即跳过可能存在于后续位置的元素

hash表实现的时候还需要提供仿函数

一个将key值转成整型(因为只有整型可以%hash表大小),一些可以直接转的比如 double、float这些就可以使用hash底层默认的仿函数,但是像string这样不能强转的类型,就需要用户提供对应的仿函数(库里面使用的不需要传仿函数,是因为专门为string搞了特化)

另一个用来获取key值,这个主要是用来适配pair类型的存储,使用key键来进行hash函数

链定址法

使用链定址法的hash表又叫做开散列哈希桶

它提供了从根本上解决冲突的方法,它使用链表将冲突的数据连接起来,并挂在哈希表的一个位置下面,此时冲突数据不再会影响到别的数据存储

链地址法实现的负载因子不再有小于1的限制,它可以在大于1的时候再进行扩容

相关推荐
敲代码的嘎仔9 小时前
数据结构算法学习day3——二分查找
java·开发语言·数据结构·学习·程序人生·算法·职场和发展
代码不停10 小时前
JavaEE多线程进阶
java·数据结构·java-ee
晨非辰10 小时前
《数据结构风云》:二叉树遍历的底层思维>递归与迭代的双重视角
数据结构·c++·人工智能·算法·链表·面试
Tisfy10 小时前
LeetCode 3217.从链表中移除在数组中存在的节点:哈希表(一次遍历)
leetcode·链表·散列表
杨福瑞12 小时前
数据结构:单链表(1)
c语言·开发语言·数据结构
Yupureki12 小时前
从零开始的C++学习生活 17:异常和智能指针
c语言·数据结构·c++·学习·visual studio
脑子不好的小菜鸟13 小时前
深入剖析 Rust `HashMap`:安全哈希 (SipHash) 与高性能冲突处理 (Swiss Table)
安全·rust·哈希算法
.柒宇.16 小时前
力扣hot100----15.三数之和(java版)
java·数据结构·算法·leetcode
杰克尼18 小时前
二分查找为什么总是写错
java·数据结构·算法