《数据结构》学习笔记-第九章 词典(call-by-value)

Hashing(哈希/散列:赖以高效组织数据并实现相关算法的重要思想)

1.原理

首先要明确为什么要使用散列。
以电话簿为例,可能的电话R=108=100M,实有的电话N=25000=25K。
如果用数组来实现电话的查询,虽然时间效率是常数,但是空间效率=N/R=0.025%,太低了不可取,所以我们需要散列。

散列原理
在这里插入图片描述
使用定址可以将关键码映射至散列空间,但是会存在冲突,即不同的关键码映射到同一个词条

2.评价标准与设计原则

在这里插入图片描述

3.设计散列表he散列函数(尽可能得降低冲突的概率,越随机越好)

(1)除余法 hash(key)=key%MM取素数时,数据对散列表的覆盖最充分,分布最均匀
在这里插入图片描述
(2)MAD法(multiply-add-divide)
在这里插入图片描述
(3)数字分析(select digits)
在这里插入图片描述
(4)平方取中(mid-square)
在这里插入图片描述
(5)
在这里插入图片描述
(6)
在这里插入图片描述
(7)(伪)随机数法(慎用!!!因为随机数发生器的不确定性,创建的散列表可移植性差)
在这里插入图片描述
在这里插入图片描述
(8)多项式法(针对字符串)
在这里插入图片描述
(9)近似多项式法(非常适用于英文字符串)

static size_t hasnCode(char s[]){
	int h=0;
	for(size_t n=strlen(s),i=0;i<n;i++){
		h=((h<<5)|h>>27);//数位变换,32位二进制转换,前5个和后27个互换位置
		h+=(int)s[i];//累计
	}
	return size_t;
} 

4.制定可行的预案,排解冲突

4.1 基本方法(封闭地址/开放地址)

(1)多槽位(multiple slots)
在这里插入图片描述
但是每个桶配备多少个槽位是难以预测的

(2)独立链(linklist-chaining/separate chaining)——封闭地址(发生冲突时申请额外的空间)
在这里插入图片描述
(3)公共溢出区(over-flow area)
在这里插入图片描述
但是一旦发生冲突,处理冲突词条的时间将正比于溢出区的规模

(4)开放地址/闭散列(散列表所占的空间在物理上始终是地址连续的一块,所有冲突在连续的空间中排解)
在这里插入图片描述
那么该如何组织查找链呢?

1.线性试探——插入
在这里插入图片描述

template <typename K,typename V> int Hashtable<K,V>::probe4Hit(const K& k){
	int r=hashCode(k) %M;//从首个桶起沿查找链,跳过所有冲突和被懒惰删除的桶
	while(hr[r]&&(k!=hr[r]->key)||!ht[r]&&laziRemoved(r))
		r=(r+1)%M;//线性试探(注意并列判断的次序,命中可能性更大者前置)
	return r;//调用者根据ht[r]是否为空,即可判断查找是否成功 
} 

2.惰性删除
在这里插入图片描述

template  <typename K,typename V> int Hashtable<K,V>::probe4Free(const K& k){
	int r=hashCode(k) %M;//从首个桶起
	while(ht[r])
		r=(r+1)%M;
		return r; 
template  <typename K,typename V> int Hashtable<K,V>::probe4Free(const K& k){
	int r=hashCode(k) %M;//从首个桶起
	while(ht[r])
		r=(r+1)%M;//沿查找链找到的第一个空桶 
	return r; //调用者根据ht[r]是否为空,即可判断查找是否成功 
}
}

4.2 改进

(1)平方试探
由于开放地址的物理结构更为紧凑,所以性能更好,对于大规模数据更有优势,但是对于线性试探会存在大量不该发生的冲突,因为它的试探位置间距太近。所以改进方式为拉大间距

在这里插入图片描述
优点 缓解数据聚集

缺点

1.破坏数据访问的局部性,若涉及外存,I/O激增(但是通常情况下,缓存页面都在若干KB左右,这里以1KB为例,如果一个桶单元记录引用,那么只需要4字节,每一个缓存页面就可以容纳1000/4约256(162)个桶单元,相应的每一次额外的I/O兑换,则要连续发生十六次冲突)

2.存在空桶会不被发现的情况
在这里插入图片描述
(装填因子为什么必须小于0.5呢?因为上图中的第二段可以看出,装填因子=6/11>0.5,导致空桶没被找出)

(2)双向平方试探
此时,我们已经可以保证,在起始于任何一个位置的平方探测我们的[M/2]上者必然会彼此互异,但是下者却得不到这样的保证,所以要进一步改进,这样可以进一步提高装填因子。
在这里插入图片描述
但是并不是所有素数都可以遍及,如下图所示(4k+3结论来源于双平方定理:任一素数p可表示为一对整数的平方和,当且仅当p%4=1)
在这里插入图片描述
(3)重散列

在这里插入图片描述

5.应用

5.1 桶/计数排序

在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值