当前位置: 首页 > news >正文

《算法导论》11.3 除法散列法、乘法散列法 11.4 开放寻址法

散列函数

一、除法散列法

1、含义:通过k除以m的余数,将关键字k映射到m个槽的某一个上,即散列函数为:h(k) = k mod m,例如m = 12,所给关键字为100,则h(k) = 4。
2、在运用除法散列法的时候,要注意避免使用某些m的值,例如不推荐m=2p,因为h(k)就是k的p个最低位的数字的h,例如225mod4 = 125mod4 = 25 mod 4。
3、选一个不太接近二的整数幂的素数,是一个非常好的选择。

二、乘法散列法

1、步骤:
(1)用关键字k呈上常数A(0<A<1),并提取KA的小数部分。
(2)第二步,用m乘以这个值,然后向下取整,总之散列函数为
在这里插入图片描述
2、优点:对于m的选择并不是特别关键,一般选择它为2的某个幂次(m = 2p
在这里插入图片描述
如图,关键字k的w位表示乘上s = A*2w的w位值。在乘积的低w位中,p个最高位构成了所需的散列值h(k),在乘积的低w位中,p个最高位构成了h(k)。

开放寻址法

一、基本内容

1、基本内容:在开放寻址法中,所有元素都放在散列表里。也就是说,每个表项要么包含动态集合的一个元素,要么包含NIL。当查找某个元素的时候,要系统性检查所有表项,直到找到所需的元素,或者直到最终查明元素不再表中。
2、优势:可以将用作链接的链表存放在散列表没有用到的槽里,但是开放寻址法本身的优势就是在于它不用指针,而是计算出要存储的槽序列。于是不用指针而省下的空间可以用来提供更多槽,减少冲突。
3、探查:为了使用开放寻址法插入一个元素,需要连续地检查散列表,称为“探查(probe)”,直到找到适合的位置插入。
(1)如何探查?
我们将散列函数扩充,使之包含探查号(从零开始)以作为其第二个输入参数,这样散列函数就变为在这里插入图片描述
,对每一个关键字k,使用开放寻址法的探查序列(prove sequence)
在这里插入图片描述
这是<0,1,…m-1>的一个排列,使得每一个表位最终都有机会成为用来插入新关键字的槽。
(2)插入关键字伪代码

HASH-INSERT(T,k)
i = 0
repeat
	j = h(k,i)
	if T[j] == NIL;//如果T[j]为NIL的话,将k填入,返回位置j即可;
		T[j] = k
		return j
	else i = i+1
until i==m
error "hash table overflow"

思路:假设伪代码中散列表T的元素是无卫星数据的关键字;关键字k等同于包含关键字k的元素。每个槽包含一个关键字或NIL。
(3)查找关键字伪代码

HASH-SEARCH(T,k)
i = 0
repeat
	j = h(k,i)
	if(T[j] == k)//找到了就直接返回
		return j
	i = i+1
until T[j]==NIL or i==m	//如果T[j]=NIL就说明k不在表中,k在表中的话就得在此处
return NIL

二、线性探查和二次探查

1、线性探查

(1)给定一个普通的散列函数在这里插入图片描述
,称之为辅助散列函数线性探查方法采用的散列函数为
在这里插入图片描述
给定一个关键字k,从T[h’(k)]探查到T[m-1],再绕到T[0],T[1]直到T[h’(k)-1],所以一共有m个不容的探查序列。
(2)线性探查比较容易实现,但是容易出现一次群集的问题,因为当一个空槽之前有i个满的槽时,该槽下一个被占用的概率为(i+1)/m,连续被占用的槽会越来越多,平均查找时间也会越来越大。

二、二次探查

(1)采用如下形式的散列函数:
在这里插入图片描述
其中h’为辅助散列函数,c1和c2为正的辅助常数,i = 0,1,…m-1。初始的探查位置为T[h’(k)],后续的探查位置要加一个偏移量,该偏移量以二次的方式依赖于i。为了充分利用散列表,要限制c1c2的值;
(2)如果两个关键字的初始探查位置相同,那么它们的探查序列也相同,因为h(k1,0)=h(k2,0)蕴含h(k1,i) = h(k2,i)。这有可能造成二次群集。初始探查位置决定整个序列,有m个不同的探查序列被用到(和线性探查一样)。

三、双重散列

(1)用于开放寻址法的最好方法之一,采用如下形式散列函数:
在这里插入图片描述
h1和h2均为辅助散列函数,初始探查位置为T[h1(k)],后续加上偏移量h2(k)再模m。
(2)为了可以查找整个散列表,值h2(k)必须要和表的大小互素:第一种办法是取m为2的幂,设计一个总产生奇数的h2;第二种办法是取m为素数,并设计一个总是返回比m小的正整数的函数h2。例如,取m为素数,
在这里插入图片描述
m’略小于m。
(3)举个例子:k=123456,m=701,m’ = 700,则由h1(k)=80,h2(k)=257,可知我们第一个探查位置为80,然后检查每第257个槽,直到找到这个关键字,或者遍历完所有的槽没找到。
(4)在这里插入图片描述
图中描述的是双重散列法的插入,这里散列表的大小是13,h1(k)=k mod 13,h2(k) = 1+(k mod 11)。因为14 mod 13 = 1,14 mod 11 = 3,因此在探查了槽1和槽5后,关键字14插入到槽9中。

相关文章:

  • 【java_wxid项目】【第八章】【Apache ShardingSphere集成】
  • CTF-PUT上传漏洞【超详细】
  • 程序人生 | 编程的上帝视角应该怎么去找
  • KingbaseES V8R3集群运维案例之---主库系统down failover切换过程分析
  • 夏日水果茶饮店如何引流?这四款饮品必学
  • ESP32_esp-idf_lvgl_V8环境搭建移植
  • 人工智能第2版学习——产生式系统2
  • Cortex-A核的异常的处理过程
  • 基于IDEA 工程项目的git实操
  • SAP 多个smartforms同时打印页码问题
  • 离线数仓搭建_03_Hadoop的配置与优化测试
  • 【设计模式】Java设计模式 - 命令模式
  • openstack-mitaka(二) 基于vmware的搭建
  • 【Vue2】VantUI项目入门教程
  • 痛苦与反思:想提升自己,却不知道该如何做
  • Angular 响应式表单之下拉框
  • Github访问慢解决办法
  • github指令
  • JDK 6和JDK 7中的substring()方法
  • JSDuck 与 AngularJS 融合技巧
  • Magento 1.x 中文订单打印乱码
  • VuePress 静态网站生成
  • 翻译:Hystrix - How To Use
  • 马上搞懂 GeoJSON
  • 学习JavaScript数据结构与算法 — 树
  • 组复制官方翻译九、Group Replication Technical Details
  • ​RecSys 2022 | 面向人岗匹配的双向选择偏好建模
  • # .NET Framework中使用命名管道进行进程间通信
  • #vue3 实现前端下载excel文件模板功能
  • #调用传感器数据_Flink使用函数之监控传感器温度上升提醒
  • $HTTP_POST_VARS['']和$_POST['']的区别
  • (C++20) consteval立即函数
  • (done) ROC曲线 和 AUC值 分别是什么?
  • (三)终结任务
  • (十六)串口UART
  • (幽默漫画)有个程序员老公,是怎样的体验?
  • (原創) 如何優化ThinkPad X61開機速度? (NB) (ThinkPad) (X61) (OS) (Windows)
  • (转)Windows2003安全设置/维护
  • .FileZilla的使用和主动模式被动模式介绍
  • .NET / MSBuild 扩展编译时什么时候用 BeforeTargets / AfterTargets 什么时候用 DependsOnTargets?
  • .NET 8.0 发布到 IIS
  • .net 设置默认首页
  • .Net+SQL Server企业应用性能优化笔记4——精确查找瓶颈
  • .net知识和学习方法系列(二十一)CLR-枚举
  • @staticmethod和@classmethod的作用与区别
  • @Validated和@Valid校验参数区别
  • [ CTF ] WriteUp-2022年春秋杯网络安全联赛-冬季赛
  • [AIGC] SQL中的数据添加和操作:数据类型介绍
  • [AutoSar]BSW_Memory_Stack_003 NVM与APP的显式和隐式同步
  • [BT]BUUCTF刷题第9天(3.27)
  • [BZOJ 2142]礼物(扩展Lucas定理)
  • [C#]使用PaddleInference图片旋转四种角度检测
  • [Docker]五.Docker中Dockerfile详解
  • [dts]Device Tree机制
  • [GDOUCTF 2023]<ez_ze> SSTI 过滤数字 大括号{等