开地址哈希表(Hash Table)的原理描述与冲突解决
在开地址哈希表中,元素存放在表本身中。这对于某些依赖固定大小表的应用来说非常有用。因为不像链式哈希表在每个槽位上有一个“桶”来存储冲突的元素,所以开地址哈希表需要通过另一种方法来解决冲突。
解决冲突的方法
在开地址哈希表中,解决冲突的方法就是探查这个表,直到找到一个可以放置元素的槽。
例如,插入一个元素时,我们探查槽位直到找到一个空槽,然后将元素插入此槽中。删除或查找一个元素时,我们探查槽位直到定位到该元素或找到一个空槽。如果在找到元素之前找到一个空槽或遍历完所有槽位,那么说明此元素在表中不存在。
我们要做的就是尽可能地减少探查的次数。究竟进行多少次探查后就停止,这主要取决于两件事:哈希表的负载因子 和 元素均匀分布的程度。
哈希表的负载因子a=n / m,n为元素个数,m为可以散列元素的槽位个数。根据开地址哈希表的定义,n不可能大于m,所以 开地址哈希表的负载因子通常小于或等于1。
假设散列是均匀的,我们能够在一个开地址哈希表中探查的槽位个数将是:1 / (1-a)
举例来说,对于一个处于半满状态的开地址哈希表来说( 负载因子为0.5),我们期望能够探查的槽位个数为1/(1-0.5)=2。
下表列示了当哈希表的负载因子趋近于1时(即表完全满时),我们期望探查的槽位数量如何显著增长。在一个对时间特别敏感的应用中,就可以通过增加哈希表的空间(槽位数)来提高探查的效率。
哈希表的性能能否接近于这个规律取决于我们是否能够近似均匀散列,这关键取决于如何选取哈希函数。
一般来说,在开地址哈希表中探查槽位的哈希函数定义为:
h(k,i) = x
其中,k是键,i是到目前为止探查的次数,x是得到的哈希编码。通常情况下,与链式哈希表一样,h会调用一个或多个具有具有相同属性的辅助哈希函数。但在开地址哈希表中,h必须具有一个额外的属性:当i从0增长到m-1(m为哈希表中槽位的个数)时,在第二次访问任何槽位之前,表中所有的槽位都必须访问过一遍;否则,就说明不需要探查所有的槽位就能找到结果。
两种探查方法:线性探查和双散列
线性探查是开地址哈希表中一种简单的探查方法,探查表中连续的槽位。正式的表述为,如果i大于0,小于m-1(m为表中的槽位个数),那么一个线性探查方法的哈希函数定义为:
h(k,i) = (h'(k)+i) mod m
函数h'是一个辅助的哈希函数,就像任何哈希函数的选择方法一样,它会尽可能地将元素随机和均匀地分布在表中。比如采用取余法,h'(k)= k mod m。如果将一个元素(k=2998)散列到表(容量m=1000),所得到的哈希编码为(998+0) mod 1000 =998(当i = 0时),(998+1) mod 1000 = 999(当i = 1时),(998+2)mod 1000 = 0(当i=2时)...依此类推。也就是说,当要插入一个键k = 2998的元素时,我们会寻找一个空的槽位,首先探查槽位998,然后999,然后0...,依此类推。
线性探查的优点是简单,而且对m没有限制,这样就可以保证所有的槽位最终都可能探查到。遗憾的是,线性探查并不能近似均匀散列。特别是当遇到和种称为基本聚集的情况时,基本聚集会产生很长的探查序列,从而使表变得越来越大。这种过度的探查会降低表的性能。
双散列
最有效地探查开地址哈希表的方法之一,就是 通过计算两个辅助哈希哈希编码的和 来得到哈希编码。正式的表述为,如果i的大小在0和m之间(m为表中槽位的个数),双散列的哈希函数定义为:
h( k, i ) = (h1(k) + i h2(k)) mod m
函数h1和h2是两个辅助哈希函数,它们与其他的哈希函数一样,也会尽可能地将元素随机和均匀的散列到表中。为了保证第二次访问任何一个槽位之前其他所有的槽位都访问过一遍,我们必须遵循如下规则:一种方法是,m必须是2次幂,让h2返回一个奇数值;另一种方法是选择m为一个素数,h2返回的值在1<= h2(k) <= m-1之间。
通常情况下,令h1(k) = k mod m,h2(k) = 1+(k mod m'),其中m'略小于m,类似等于m-1或m-2。例如,如果哈希表槽位数m=1699(素数),要散列的键k=15385,探查到的槽位为(940+0X113) mod 1699 = 94(当i=0时),以及之后每隔113位置的槽位(随i的增加)。
双散列的优点是,它能够在表中探查并产生较好的元素分布。其缺点是,必须限制m的值,这样才能够保证在一系列探查中访问表中所有槽位之后才会再次探查任何槽位。
开地址哈希表(Hash Table)的原理描述与冲突解决的更多相关文章
- 开地址哈希表(Hash Table)的接口定义与实现分析
开地址哈希函数的接口定义 基本的操作包括:初始化开地址哈希表.销毁开地址哈希表.插入元素.删除元素.查找元素.获取元素个数. 各种操作的定义如下: ohtbl_init int ohtbl_init ...
- 算法与数据结构基础 - 哈希表(Hash Table)
Hash Table基础 哈希表(Hash Table)是常用的数据结构,其运用哈希函数(hash function)实现映射,内部使用开放定址.拉链法等方式解决哈希冲突,使得读写时间复杂度平均为O( ...
- PHP关联数组和哈希表(hash table) 未指定
PHP有数据的一个非常重要的一类,就是关联数组.又称为哈希表(hash table),是一种很好用的数据结构. 在程序中.我们可能会遇到须要消重的问题,举一个最简单的模型: 有一份username列表 ...
- 词典(二) 哈希表(Hash table)
散列表(hashtable)是一种高效的词典结构,可以在期望的常数时间内实现对词典的所有接口的操作.散列完全摒弃了关键码有序的条件,所以可以突破CBA式算法的复杂度界限. 散列表 逻辑上,有一系列可以 ...
- 什么叫哈希表(Hash Table)
散列表(也叫哈希表),是根据关键码值直接进行访问的数据结构,也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映射函数叫做散列函数,存放记录的数组叫做散列表. - 数据结构 ...
- 数据结构 哈希表(Hash Table)_哈希概述
哈希表支持一种最有效的检索方法:散列. 从根来上说,一个哈希表包含一个数组,通过特殊的索引值(键)来访问数组中的元素. 哈希表的主要思想是通过一个哈希函数,在所有可能的键与槽位之间建立一张映射表.哈希 ...
- 哈希表(Hash table)
- 哈希表(Hash Table)原理及其实现
原理 介绍 哈希表(Hash table,也叫散列表), 是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映 ...
- 【Python算法】哈希存储、哈希表、散列表原理
哈希表的定义: 哈希存储的基本思想是以关键字Key为自变量,通过一定的函数关系(散列函数或哈希函数),计算出对应的函数值(哈希地址),以这个值作为数据元素的地址,并将数据元素存入到相应地址的存储单元中 ...
随机推荐
- Head First设计模式之模板方法模式
一.定义 在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变算法结构的情况下,重定义该算法中的某些特定步骤. 比较通俗的说法,子类决定如何实现算法中的某些步骤,比如两个一连串 ...
- APP网络测试要点和弱网模拟
当前APP网络环境比较复杂,网络制式有2G.3G.4G网络,还有越来越多的公共Wi-Fi.不同的网络环境和网络制式的差异,都会对用户使用app造成一定影响.另外,当前app使用场景多变,如进地铁.上公 ...
- MicroPython教程之TPYBoard v102 CAN总线通信
0x00前言 CAN是控制器局域网络(ControllerAreaNetwork,CAN)的简称,是ISO国际标准化的串行通信协议.CAN总线结构简单,只需2根线与外部相连,并且内部集成了错误探测和管 ...
- angular4.0如何引入外部插件2:declare方案
前面有个<angular4.0如何引入外部插件1:import方案>,但是有局限,因为方案1需要用到@types这个东西. 但是并不是每一个插件都有@types,所以现在写个方案2. 拿引 ...
- 第十章:Python の 网络编程基础(二)
本課主題 Python中的作用域补充 socketserver 源码 线程的介绍和操作实战 进程的介绍和操作实战 协程的介绍和操作实战 本周作业 Python中的作用域补充 Python世界里沒有块级 ...
- Mysql 启动遇到 The server quit without updating PID file (/[FAILED]l/mysql/data/021rjsh216086s.pid)和Attempted to open a previously opened tablespace
今天在测试服务器做调试的时候,遇到Mysql的启动问题,好像是PID文件找不到了. 不科学啊,前几天还好好的呀,我也没怎么乱搞啊,然后一通百度,找到了几个解决办法. 1.有可能是已经存在mysql进程 ...
- BaseServer的介绍
服务器类型 5种类型:BaseServer,TCPServer,UnixStreamServer,UDPServer,UnixDatagramServer.注意:BaseServer不直接对外服务. ...
- C#学习笔记-基础知识篇(不定期更新)
1.父类必须包含构造函数么? 父类必须要有一个构造函数,有参无参都可以. 构造函数是对象的基本,没有构造函数就没有对象,若父类中显示的有参数的构造函数,在子类继承就必须写一个构造函数来调用父类的构造函 ...
- Mysql与PostgreSQL小pk
普通增删改查 表结构及数据都极其简单,命名也及其不讲究.均为默认配置,mysql表默认InnoDB引擎.表x包含三个int字段a b c,100W条数据均a=1 b=2 c=3 sql语句 建表: c ...
- MYBATIS常用的sql事例
今天整理了一下在项目中经常用到的mybatis的xml文件的sql语句: 读者:有sql基础. <?xml version="1.0" encoding="UTF- ...