引言
HashTable-散列表/哈希表,是根据关键字(key)而直接访问在内存存储位置的数据结构。 它通过一个关键值的函数将所需的数据映射到表中的位置来访问数据,这个映射函数叫做散列函数,存放记录的数组叫做散列表,也就是哈希表。
构造哈希表的几种方法
直接定址法
取关键字的某个线性函数为散列地址,Hash(Key)= Key 或 Hash(Key)= A*Key + B,A、B为常数。 直接定址所得集合和关键字集合的大小相同,所以对于不同的关键字不会产生冲突。
只解释第一个,后边的就都很容易理解了。其实这个方法我们之前肯定是见过而且用过的:比如计数排序的时候,我们定义一个数组,以待排元素的值减去最小值作为下标,元素出现次数作为数据存储,然后遍历一遍原数组,便得到所有元素的出现次数,再依次将它们输出,就是有序的了。我们这里的下标就是散列函数中的key。只不过这种方法不太好,一般不太用。比如只有三个数据:0,1,1000,那么就需要1000-0+1 = 1001个元素大小的数组来存储,我们都知道浪费就是可耻嘛!
例如:有一个1岁到100岁的人口数字统计表,其中年龄作为关键字,哈希函数取关键字自身:
除留余数法
取关键值被某个不大于散列表长m的数p除后的所得的余数为散列地址。Hash(Key)= Key % P。最简单,也最常用。
平方取中法
取关键字平方后的中间几位为哈希地址。通常在选定哈希函数时不一定能知道关键字的全部情况,取其中哪几位也不一定合适,而一个数平方后的中间几位数和数的每一位都相关,由此使随机分布的关键字得到的哈希地址也是随机的。取的位数由表长决定。
折叠法
将关键字分隔成位数相同的几部分(最后一部分的位数可以不同),然后取这几部分的叠加和(舍去进位)作为哈希地址。
随机数法
选择一个随机函数,取关键字的随机函数值作为它的哈希地址。即H(Key)=random(Key)。通常关键字长度不等时采用此法较恰当。
数字分析法
假设关键字是以r为基的数(例如以10为基的十进制数),并且哈希表中可能出现的关键字都是知道的,则可取关键字的若干位组成哈希地址。
哈希冲突/哈希碰撞
不同的Key值经过哈希函数Hash(Key)处理以后可能产生相同的值哈希地址,我们称这种情况为哈希冲突。
既然有冲突,那么就要解决冲突。有四种方法:
闭散列法/开放定址法
这种方法又分两种:线性探测与二次探测
线性探测就是当得到一个key的散列地址后发现元素已经存在,则向相邻的下一个位置去放。如果下一个位置依然被占了,继续向下找,知道找到一个为空的位置,放,。二次探测的二次是二次方的意思,即在第一次哈希地址的基础上加i的平方。
再哈希法
RHi是不同的哈希函数,即在地址冲突时计算另一个哈希地址,直到冲突不再发生。
哈希桶/开链法
将所有哈希地址相同的记录存储在同一线性表中,如图:
建立一个公共溢出区
不管它们由哈希函数得到的哈希地址是是什么,一旦发生冲突,都填入溢出表。
实现
趁着复习,实现了一份代码,托管在GitHub上,附上开源链接:
https://github.com/Fireplusplus/Data-Structure/blob/master/HashTable.cpp
哈希笔记
最新推荐文章于 2024-11-18 23:23:43 发布