前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >散列表 - Hash Table

散列表 - Hash Table

作者头像
caoqi95
发布2019-03-28 12:05:15
5170
发布2019-03-28 12:05:15
举报

「总结自《Grokking Algotithms》这本书第五章内容」

散列函数

哈希表(Hash Table),学名散列表。散列表最核心的部分就是散列函数。有了散列函数,无论你给它什么输入数据,它都还你一个数字。专业一点的话,就是散列函数将输入映射到数字

散列函数必须满足以下条件:

  • 必须是一致的。即对于同样的输出数据,都返回相同的结果。比如,每次输入 apple,返回结果都是 4。
  • 应将不同的输入映射到不同的输出。如果一个散列表无论对于什么输入,返回的结果都是 1,那它就不是一个好的散列表。一个好的散列表应该对于不同的输入映射到不同的数字。

散列表

散列函数表示了一种映射关系。可以用这种映射关系来建立一个商品价格存储的表。而存储这种映射记录的表就是散列表。散列表由键和值组成。例如,在建立的商品价格列表中,键就是商品名,值就是商品对应的价格。在Python 中,使用字典(dict)就可以建立一个散列表:

代码语言:javascript
复制
>>> food = dict()
>>> food["apple"]=0.67
>>> food["milk"]=2.18
>>> food["tea"]=24.4
>>> food
{'apple': 0.67, 'milk': 2.18, 'tea': 24.4}


>>> food['apple']
0.67
>>> food['milk']
2.18
>>> food['tea']
24.4

散列表可以用于很多地方。比如,用于电话簿的查找;用于浏览器缓存;还能用于防止重复。

冲突

前面提到散列函数,应该将不同的输入映射到不同的输出。但实际上,这很难做到。有时候会发生冲突,即:给两个键分配同一个位置。这就引起了问题,后面保存的值会将之前的值给覆盖掉,使之前的键,不能对应正确的值。

产生冲突了有解决办法吗?当然有,最简单的方法如下:如果两个键映射到了同一个位置,就在这个位置存储一个链表。但是这种解决方法存在弊端。如果该位置上的链表很长,则查找的时间就会很长。而除这个位置外,散列表其他位置的查找时间则依然很快。如果将所有的键都对应到一个值的位置上,该值的位置上用一个链表来连接所有的值。那么就和一开始就将所有的值都存储在链表中一样,查找的速度会很慢。

这里可以看出,如何设计散列函数是很重要的。最理想的状态是,将所有的键都均匀地映射到散列表的不同位置上。而且,如果散列函数设置好的话,链表就不会很长而导致速度很慢。

性能

在平均情况下,散列表执行各种操作的时间都为 O(1),即为常量时间。常量时间不并不意味着马上,而是说不管散列表有多大,所需的时间都相同。而在最糟的情况下,散列表执行各种操作的时间都为 O(n),即为线性时间。下面是散列表和数组,链表的对比:

数组

链表

散列表(平均情况)

散列表(最糟情况)

插入

O(n)

O(1)

O(1)

O(n)

查找

O(1)

O(n)

O(1)

O(n)

删除

O(n)

O(1)

O(1)

O(n)

在平均情况下,散列表的查找速度与数组一样快,而插入和删除都与链表一样快,这相当于吸收了数组和链表两者的优点。但在最糟的情况下,是两者中的最差者,所有的操作都很慢。

所以,在使用散列表的时候,要避开最糟的情况。即,需要避开冲突。避开冲突有下面两种办法:

  • 降低填装因子
  • 使用良好的散列函数

填装因子

什么是填装因子呢?很简单,公式如下:

\frac{散列表包含的元素数}{位置总数}
\frac{散列表包含的元素数}{位置总数}

在散列表中,使用数组来存储数据。因此,需要计算数组中被占用的位置数。比如,一共有 10 个位置,而被元素占用的为 2 个,填装因子就为 2 / 10。最佳的情况是:10 个位置恰好被存在的 10 个元素占用,填装因子为 1。如果为 5 个位置的话,填装因子将为 2。即,散列表中的位置不够用,不可能让每个元素都有自己的位置。

所以,填装因子大于 1 意味着元素数量超过了数组的位置数量。一旦填装因子开始增大(经验表明大于 0.7 的时候),就需要在散列表中添加位置,即调整长度。这是一种非常麻烦的方法,一旦不够用就需要调整长度,开销很大,没人愿意频繁地做这种事。

良好的散列函数

上面的方法很麻烦,让我们来看看第二种方法。什么样的散列函数是良好的呢?良好的散列函数能够让数组中的值呈均匀分布,而糟糕的散列函数则会让值扎堆,导致大量的冲突。

现实生活中,有一个函数非常好用 - SHA 函数。感兴趣的可以深入研究一下。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.01.28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 散列函数
  • 散列表
  • 冲突
  • 性能
  • 填装因子
  • 良好的散列函数
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档