Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >什么是散列表(哈希表)?

什么是散列表(哈希表)?

作者头像
编程珠玑
发布于 2019-07-12 06:10:55
发布于 2019-07-12 06:10:55
6500
举报
文章被收录于专栏:编程珠玑编程珠玑

前言

假设你们班级100个同学每个人的学号是由院系-年级-班级和编号组成,例如学号为01100168表示是1系,10级1班的68号。为了快速查找到68号的成绩信息,可以建立一张表,但是不能用学号作为下标,学号的数值实在太大。因此将学号除以1100100取余,即得到编号作为该表的下标,那么,要查找学号为01100168的成绩的时候,只要直接访问表下标为68的数据即可。这就能够在O(1)时间复杂度内完成成绩查找。

实际上这里就用到了散列的思想。本文重在介绍散列的思想以及散列需要考虑的问题。

散列表(哈希表)

理想散列表(哈希表)是一个包含关键字的具有固定大小的数组,它能够以常数时间执行插入,删除和查找操作

  • 每个关键字被映射到0到数组大小N-1范围,并且放到合适的位置,这个映射规则就叫散列函数
  • 理想情况下,两个不同的关键字映射到不同的单元,然而由于数组单元有限,关键字范围可能远超数组单元,因此就会出现两个关键字散列到同一个值得时候,这就是散列冲突

实例演示

通过前面的描述,我们已经了解了一些基本概念,现在来看一个实例。 假设有一个大小为7的表,现在,要将13,18,19,50,20散列到表中。

  • 选择散列函数,例如使用hash(x)=x%7作为散列函数
  • 计算数据散列值,并放到合适的位置

计算13 % 7得到6,因此将13放到下标为6的位置:

0

1

2

3

4

5

6

13

计算18 % 7得到4,因此将18放到下标为4的位置:

0

1

2

3

4

5

6

18

13

计算19 % 7得到5,因此将19放到下标为5的位置:

0

1

2

3

4

5

6

18

19

13

计算50 % 7得到1,因此将50放到下标为1的位置:

0

1

2

3

4

5

6

50

18

19

13

计算20 % 7得到6,因此将20放到下标为6的位置,但是此时6的位置已经被占用了,因此就产生了散列冲突,关于散列冲突的解决,我们后面再介绍。

将数据散列之后,如何从表中查找呢?例如,查找数值为50的数据位置,只需要计算50 % 7,得到下标1,访问下标1的位置即可。但是如果考虑散列冲突,就没有那么简单了。

通过这个实例,了解了以下几个概念:

  • 散列函数,散列函数的选择非常重要
  • 散列冲突,涉及散列表时,因尽量避免散列冲突,对于冲突也要有好的解决方案
  • 快速从散列表中查找数据

冲突解决

解决散列冲突通常有以下几种方法:

  • 拉链法
  • 开放定址法
  • 再散列
拉链法

分离链接法的做法是将同一个值的关键字保存在同一个表中。例如,对于前面:

0

1

2

3

4

5

6

50

18

19

13

如果再要插入元素20,则在下标为6的位置存储表头,而表的内容是13和20。

这种方法的特点是需要另外分配新的单元来存储散列到同一个位置的数据。

查找的时候,除了根据计算出来的散列值找到对应位置外,还需要在链表上进行搜索。而在单链表上的查找速度是很慢的。另外散列函数如果设计得好,冲突的概率其实也会很小

开放定址法

而开放定址法的思想是,如果冲突发生,就选择另外一个可用的位置

而开放定址法中也有常见的几种策略。

  • 线性探测法

还是以前面的为例:

0

1

2

3

4

5

6

50

18

19

13

如果此时再要插入20,则20 % 7 = 6,但是6的位置已有元素,因此探测下一个位置(6+1)%7,在这里就是下标为0的位置。因此20的存储位置如下:

0

1

2

3

4

5

6

20

50

18

19

13

但这种方式的一个问题是,可能造成一次聚集,因为一旦冲突发生,为了处理冲突就会占用下一个位置,而如果冲突较多时,就会出现数据都聚集在一块区域。这样就会导致任何关键字都需要多次尝试才可能解决冲突。

  • 平方探测法

顾名思义,如果说前面的探测函数是F(i)= i % 7,那么平方探测法就是F(i)= (i^2 )% 7。 但是这也同样会产生二次聚集问题。

  • 双散列

为了避免聚集,在探测时选择跳跃式的探测,即再使用一个散列函数,用来计算探测的位置。假设前面的散列函数为hash1(X),用于探测的散列函数为hash2(X),那么一种流行的选择是F(i) = i * hash2(X),即第一次冲突时探测hash1(X)+hash2(X)的位置,第二次探测 hash1(X)+2hash2(X)的位置。

可以看到,无论是哪种开放定址法,它都要求表足够大。

再散列

我们前面也说到,散列表可以认为是具有固定大小的数组,那么如果插入新的数据时散列表已满,或者散列表所剩容量不多该怎么办?这个时候就需要再散列,常见做法是,建立一个是原来两倍大小的散列表,将原来表中的关键字重新散列到新表中。

散列表的应用

散列表应用很广泛。例如做文件校验或数字签名。当然还有快速查询功能的实现。例如,redis中的字典结构就使用了散列表,使用MurmurHash算法来计算字符串的hash值,并采用拉链法处理冲突,,当散列表的装载因子(关键字个数与散列表大小的比)接近某个大小时,进行再散列

总结

一个设计良好的散列表能够几乎在O(1)时间复杂度内完成插入,删除和查找,但前提是散列函数设计得足够优雅,以及有着合适散列冲突解决方案。常见冲突解决方案有:

  • 拉链法
  • 开放地址检测法

其中拉链法在实际中是很常见的一种解决方案。另外本文重点说明什么是散列表(哈希表),因此没有涉及具体的代码,后面将会通过实例来看散列表的实际应用。

参考

数据结构与算法分析》 《redis设计与实现》 https://en.wikipedia.org/wiki/Hash_table

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-05-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 编程珠玑 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
散列表(哈希表)
版权声明:本文为博主原创文章,转载请注明博客地址: https://blog.csdn.net/zy010101/article/details/83998492
zy010101
2019/05/25
7440
哈希表的实现--C++
哈希(hash)又称散列,是一种组织数据的方式。从译名来看,有散乱排列的意思。本质就是通过哈希函数把关键字Key跟存储位置建立一个映射关系,查找时通过这个哈希函数计算出Key存储的位置,进行快速查找。
小志biubiu
2025/02/27
1420
哈希表的实现--C++
【C++】哈希表的实现
哈希(hash)⼜称散列,是⼀种组织数据的⽅式。从译名来看,有散乱排列的意思。本质就是通过哈希函数把关键字Key跟存储位置建⽴⼀个映射关系,查找时通过这个哈希函数计算出Key存储的位置,进⾏快速查找。
用户11290673
2025/01/13
1070
【C++】哈希表的实现
散列表
是根据键 (Key) 而直接访问在内存存储位置的数据结构。也就是说,它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录,这加快了查找速度。这个映射函数称做散列函数,存放记录的数组称做散列表。
周三不加班
2019/09/03
7150
散列表
【C++】哈希表的实现
哈希(hash)⼜称散列,是⼀种组织数据的⽅式。从译名来看,有散乱排列的意思。本质就是通过哈希 函数把关键字Key跟存储位置建⽴⼀个映射关系,查找时通过这个哈希函数计算出Key存储的位置,进 ⾏快速查找。
用户11375356
2024/12/24
1360
【C++】哈希表的实现
散列表
http://blog.csdn.net/yyxaf/article/details/7527878 搜索关键词:散列函数、散列表、哈希函数、哈希表、Hash函数、Hash表 散列方法不同于顺序查找、二分查找、二叉排序树及B-树上的查找。它不以关键字的比较为基本操作,采用直接寻址技术。在理想情况下,无须任何比较就可以找到待查关键字,查找的期望时间为O(1)。 散列表的概念 1、散列表 设所有可能出现的关键字集合记为U(简称全集)。实际发生(即实际存储)的关键字集合记为K(|K|比|U|小得多)。 散列方
用户1624346
2018/04/17
1K0
哈希表
要查一个数在数组中的位置,那可是太费劲了,只能从头开始一个个的比较,直到找到相等的才算完事。
武师叔
2022/09/26
4770
哈希表
重温数据结构:哈希 哈希函数 哈希表
该文介绍了计算机科学中的哈希表(Hash Table)及其在编程中的应用。哈希表是一种数据结构,可以高效地完成查找、插入、删除等操作。文章还介绍了哈希函数、哈希冲突、拉链法等概念。
张拭心 shixinzhang
2018/01/05
2.7K1
重温数据结构:哈希 哈希函数 哈希表
C++ —— 哈希详解 - 开散列与闭散列
1. 从发⽣冲突的位置开始,依次线性向后探测,直到寻找到下⼀个没有存储数据的位置为⽌,如果⾛到哈希表尾,则回绕到哈希表头的位置(回绕方法就是进行取模)
迷迭所归处
2024/11/19
740
C++ —— 哈希详解 - 开散列与闭散列
数据结构基础详解:哈希表【理论计算篇】开放地址法_线性探测法_拉链法详解
散列表,又称哈希表。是一种数据结构,特点是:数据元素的关键字与其存储地址直接相关。
小徐在进步
2024/10/08
4140
数据结构基础详解:哈希表【理论计算篇】开放地址法_线性探测法_拉链法详解
解决哈希冲突
假设hash表的大小为9(即有9个槽),现在要把一串数据存到表里:5,28,19,15,20,33,12,17,10
sunsky
2020/10/28
1.5K0
散列表
总结:这上面三种方法都是在同一个数组中进行处理,没有超过数组的范畴,改变的都是d的取值方式
大忽悠爱学习
2021/11/15
6390
进阶 | 我实现了javascript 哈希表,并进行性能比较
前端爱好者的聚集地 javascript的对象就是一个哈希表,为了学习真正的数据结构,我们还是有必要自己重新实现一下。 基本概念 哈希表(hash table )是一种根据关键字直接访问内存存储位置的数据结构,通过哈希表,数据元素的存放位置和数据元素的关键字之间建立起某种对应关系,建立这种对应关系的函数称为哈希函数。 哈希表的构造方法 假设要存储的数据元素个数是n,设置一个长度为m(m > n)的连续存储单元,分别以每个数据元素的关键字Ki(0<=i<=n-1)为自变量,通过哈希函数hash(Ki),把
用户1097444
2022/06/29
6870
进阶 | 我实现了javascript 哈希表,并进行性能比较
散列表(Hash Table)
散列表是一种以平均O(1)时间插入、删除和查找的数据结构,可是类似于findMax,findMin等操作则需要以O(N)的时间才能完成
None_Ling
2018/10/24
6750
散列表(Hash Table)
哈希相关知识再学习
在平时工作和源码学习的过程中经常遇到哈希相关的问题,每次都会上网找资料回忆哈希相关的知识点。趁这机会记录下来,防止以后又忘记了!!
静默加载
2020/05/29
7740
【数据结构】什么是哈希表(散列表)?
在正式开始深入了解哈希表之前呢, 我想带大家先回忆一下生活中咱们的这个"老朋友"。可能你会感到诧异, 我怎么会和它是"老朋友"呢? 别急, 其实你的生活中常常会出现哈希的身影,只是你没有细心观察罢了,不信你看下面几个场景对你来说是不是非常熟悉呢:
修修修也
2024/10/06
2430
【数据结构】什么是哈希表(散列表)?
数据结构--散列表 Hash Table
线性探测法,当空闲位置越来越少时,几乎要遍历整个散列表,接近O(n)复杂度 b. 二次探测:每次的步长是 1, 2, 4, 8, 16,… c. 双重散列:使用多个散列函数,先用第一个,如果位置被占,再用第二个散列函数。。。直到找到空闲位置 不管哪种方法,空闲位置不多了,冲突概率会大大提高,尽量保证有一定比例的空闲(用装载因子表示,因子越大,空位越少,冲突越多,散列表性能下降)
Michael阿明
2021/02/20
3480
数据结构--散列表 Hash Table
由散列表到BitMap的概念与应用(一)
散列表是种数据结构,它可以提供快速的插入操作和查找操作。第一次接触散列表时,它的优点多得让人难以置信。不论散列表中有多少数据,插入和删除只需要接近常量的时间即O(1)的时间级。实际上,这只需要几条机器指令。
aoho求索
2018/12/05
2.2K0
【高阶数据结构】哈希表详解
该方式即为哈希(散列)方法,哈希方法中使用的转换函数称为哈希(散列)函数,构造出来的结构称为哈希表(Hash Table)(或者称散列表)
YIN_尹
2024/01/23
1.1K0
【高阶数据结构】哈希表详解
哈希冲突常用解决方法
哈希算法:根据设定的哈希函数H(key)和处理冲突方法将一组关键字映象到一个有限的地址区间上的算法。也称为散列算法、杂凑算法。
恋喵大鲤鱼
2020/11/12
4.4K0
哈希冲突常用解决方法
相关推荐
散列表(哈希表)
更多 >
领券
💥开发者 MCP广场重磅上线!
精选全网热门MCP server,让你的AI更好用 🚀
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档