哈希表简介:
哈希表(Hash table,也叫散列表)
,是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
记录的存储位置 = f(关键字)
这里的对应关系f 称为散列函数,又称为哈希(Hash函数),采用散列技术将记录存储在一块连续的存储空间中,这块连续存储空间称为散列表或哈希表(Hash table)。
当使用哈希表进行查询的时候,就是再次使用哈希函数将key转换为对应的数组下标,并定位到该空间获取value
,使之能充分利用到数组的定位性能进行数据定位。
- 数组的特点是:寻址容易,插入和删除困难;
- 链表的特点是:寻址困难,插入和删除容易。
1. 哈希函数的构造方法:
直接定址法
:取关键字或关键字的某个线性函数值为哈希地址。数字分析法
:若关键字是以r为基的数(例如:以10为基的十进制数),且哈希表中可能出现的关键字都是事先知道的,那么可以取关键字的若干数位组成哈希地址。平方取中法
:取关键字平方后的中间几位为哈希地址折叠法
:将关键字分割成位数相同的几部分(最后一部分的位数可不同),然后取这几部分的叠加和(舍去进位)作为哈希地址。适用于关键字位数比较多,且关键字中每一位上数字分布大致均匀时。除留余数法
:取关键字被某个不大于哈希表表长m的数p除后所得余数为哈希地址(p为素数)
H(key)=key MOD p,p<=m (最简单,最常用)p的选取很重要
一般情况,p可以选取为质数或者不包含小于20的质因数的合数(合数指自然数中除了能被1和本身整除外,还能被其他数(0除外)整除的数)。随机数法
:选择一个随机函数,取关键字的随机函数值作为它的哈希地址,即H(key) = random (key)
,其中random为随机函数。适用于关键字长度不等时。
2. 总结哈希函数构造时需要考虑的因素:
- 计算哈希地址所需要的时间
- 关键字的长度
- 哈希表的大小
- 关键字的分布情况
- 记录的查找频率
3. 哈希冲突:
哈希是通过对数据进行再压缩来提高效率的一种解决方法。由于通过哈希函数产生的哈希值是有限的,所以当数据较多的时候会导致经过哈希函数处理后仍然有不用的数据对应不同的值,于是就会产生哈希冲突。
**产生哈希冲突的影响因素:**装填因子(装填因子 = 数据总数 / 哈希长)、哈希函数、处理冲突的方法
解决哈希冲突的方法:
开放地址方法
:线性探索
:按顺序决定值是,如果某数据的值已经存在,就在原来值的基础上往后加一个单位,至不再产生哈希冲突。再平方探索
:按顺序决定值时,如果某数据的值已经存在,则在原来值的基础上先加1的平方个单位,若仍然存在则减1的平方个单位。随之是2的平方,3的平方等等。直至不发生哈希冲突。伪随机探测
:顺序决定值是,若某数据的值已经存在,可以通过随机函数随机生成一个数,在原来值的基础上加上随机数,至不再发生随机冲突。
拉链法(又叫链地址法)
:
该图左边是个数组,数组的每个成员包括一个指针,指针指向链表的头,链表也可能为空。能根据元素的特征等把元素分配到不同的链表中去,因此可以根据这些特征找到正确的链表从而在链中找到需要的元素。
优点:
- 拉链法处理冲突简单,无堆积现象(非同义词决不会发生冲突),因此平均查找长度较短;
- 其链表上的结点空间是动态申请的,所以更适合于造表前无法确定表长的情况;
- 开放定址法为减少冲突,要求装填因子α较小,故当结点规模较大时会浪费很多空间。而拉链法中可取α≥1,且结点较大时,拉链法中增加的指针域可忽略不计,因此节省空间;
- 在用拉链法构造的散列表中,删除结点的操作易于实现(只要简单地删去链表上相应的结点即可)。
缺点: - 指针占用较大空间时,会造成空间浪费
建立公共溢出区
:使用建立的公共溢出区存储所有哈希冲突的数据再哈希法
:对于冲突的哈希值再次进行哈希处理,直到没有哈希冲突
4. 哈希表的查找:
首先确定key的值,然后直接计算出这个元素在集合中的位置。哈希表的查询速度很快,大约是O(1)的时间复杂度,当需要查找较多的数据时,哈希表的查找速度会远大于树的查找速度,树的查找速度大约为O(n) 的时间复杂度,而且哈希表与树相比也更容易编程实现。
5. 哈希表的删除:
链地址法可以直接删除元素。
6. 有关哈希表的扩展:
d-lest-hashing
中的d指的是多个的意思,意味着哈希函数的个数是d,在d-left-hashing
中,整个哈希表被分成了从左向右依次相邻的子表,每个子表对应一个相互独立的哈希函数。当有key加入时,就会被d个哈希函数同时计算,并产生d个相互独立的位置,最后经比较将key加入负载最轻的位置中。倘若负载最轻的位置有多个,那么就将key加入到最左边的负载最轻的子表中去。但是,如果要查找一个key也是需要查找d个位置。以此看来引入d-left-hashing
是为了解决负载均衡的问题。
使用d-left-hashing
可以让存储的信息分布均匀,从而用更小的空间来存储同样多的信息。
js 中HashMap 的一些知识
//hashMap在js中的使用
function HashMap() {
//定义长度
var length = 0;
//创建一个对象
var obj = new Object();
//判断Map是否为空
this.isEmpty = function() {
return length == 0;
};
//判断对象中是否包含给定Key
this.containsKey = function(key) {
return (key in obj);
}
//判断对象中是否包含给定的Value
this.containsValue = function(value) {
for(var key in obj) {
if(obj[key] == value) {
return true;
}
}
return false
};
//向map中添加数据
this.put = function(key, value) {
if(!this.containsKey(key)) {
length++;
}
obj[key] = value;
};
//根据给定的key获得Value
this.get = function(key) {
return this.containsKey(key)?obj[key]: null;
};
//根据给定的Key删除一个值
this.remove = function(key) {
if(this.containsKey