Hash table

Hash table

在计算机科学中,hash table,也被称为 hash map,是一种数据结构,它实现了 associative arraydictionary。它是一种映射键到值的抽象数据类型。哈希表使用 hash function 来计算一个 index,也被称为 hash code,到一个 bucketsslots 的数组中,从其中可以找到想要的值。在查找过程中,键被散列 (hashed),散列的结果表示对应的值存储在哪里。

在计算机科学中,associative arraymapsymbol table,或 dictionary 是一种抽象数据类型,用于存储pairs 的集合,每个可能的键在集合中至多只出现一次。

理想情况下,哈希函数将每个键分配到唯一的 bucket 中,但是大部分的哈希表设计都使用不完美的哈希函数,这可能导致 collisions,哈希函数对不同的键生成了相同的 index。这样的碰撞通常以某种方式被容纳。

在一个维度良好的哈希表中,每次查找的平均时间复杂度与存储在表中的元素个数无关。许多哈希表的设计也允许键值对的随意插入和删除,每次操作成本平均分摊后为常数。

散列是一个时间与空间间权衡的例子。如果内存是无限的,整个键能被直接作为 index 来定位它的值,只需要一次内存的访问。换句话说,如果可用的时间是无限的,值可以在不考虑键的情况下存储,binary searchlinear search 能被用于检索元素。

在很多情况下,哈希表较 search tree 或其他表查询结构有更高的平均效率。因此,它被广泛的应用到多种计算机软件中,特别是对于 associate arraysdatabase indexingcaches,和 sets

Overview

一种 associate array,存储一系列键值对,并允许插入,删除,和查找,约束为键唯一。在哈希表的 associate array 实现中,数组 A 长度为 m,被 n 个元素部分填充,m >= n。值 x 存储与 index 位置 A[h(x)],h 是哈希函数,h(x) < m。 在合理的假设下,哈希表较 self-balancing binary search tree 在搜索,删除和插入操作方面有更好的 time complexity

哈希表通常也被用来实现 sets,通过缺省每个键存储的值,仅追踪键是否存在。

Load factor

load factor a 是哈希表的一个关键统计量,其定义如下:
l o a d f a c t o r ( a ) = n / k , load factor (a) = n/k, loadfactor(a)=n/k,
其中,

  • n 是哈希表中占据条目的数目。
  • k 是 buckets 的数量。

哈希表性能的恶化与负载因子 a 相关。因此当负载因子 a 接近 1 时,哈希表调整大小或重新散列。哈希表在负载因子降至 amax/4 也会进行大小调整。负载因子 a 的可接受范围应该是 0.6 - 0.75。

Hash function

哈希函数 h 映射键 h 的全集 U:U->{0, …, m - 1} 到哈希表内的数组索引或槽中, h ( x ) ∈ 0 , . . . , m − 1 {\displaystyle h(x)\in {0,...,m-1}} h(x)0,...,m1,其中 x ∈ S {\displaystyle x\in S} xS 且 m < n。便利的哈希函数实现基于 integer universe assumption,表中的所有元素都源自 U = {0, …, u - 1},u 的 bit length 受限于计算机架构的 word size

完美的哈希函数 h 被定义为一个单射函数,S 中每个元素都映射到 0,…,m - 1 的一个唯一值上。如果预先知道所有的键,就能创建完美的哈希函数。

Integer universe assumption

Integer universe assumption 中使用的哈希方案包括通过除法散列,通过乘法散列,universe hashingdynamic perfect hashingstatic perfect hashing。然而,通过除法进行散列是最常用的方案。

Hasing by division

除法哈希方案如下:
h(x) = M mod n
其中,M 是哈希摘要,x 属于 S,n 是表的大小。

Hashing by multiplication

乘法哈希方案如下:
h ( k ) = ⌊ n ( ( M A )   m o d   1 ) ⌋ {\displaystyle h(k)=\lfloor n{\bigl (}(MA){\bmod {1}}{\bigr )}\rfloor } h(k)=n((MA)mod1)
其中,A 为实数常量。乘法哈希的优点之一是 m 并不重要

Choosing a hash function

哈希值得均匀分布是哈希函数的基本需求。非均匀分布增加了冲突的数量和解决他们的成本。均匀性有时很难通过设计来保证,但可以使用统计检验来进行经验评估。

只有应用程序中出现的表大小需要均匀分布。特别是,如果使用动态调整表大小,将表大小精确地翻倍或减半,那么只有当大小为2的幂时,哈希函数才需要均匀。在这里,索引可以计算为哈希函数的某个比特范围。另一方面,一些哈希算法更喜欢将大小设置为质数。

对于开放寻址方案,哈希函数也应该避免聚集,即将两个或多个键映射到连续的槽上。这种聚集可能会导致查找成本飙升,即使负载因子很低,碰撞也不频繁。流行的乘法哈希被认为具有特别糟糕的聚类行为

*K-independent hashing * 提供了一种方法来证明某个哈希函数对于给定类型的哈希表没有坏的键集。一些 K-independence 的结果是已知的冲突解决方案,如线性探测和 cuckoo 哈希。由于 K-independence 可以证明哈希函数是有效的,因此可以专注于寻找可能最快的哈希函数。

Collision resolution

使用哈希的搜索算法由两部分组成,第一部分是计算哈希函数,将搜索的键转换为数组索引。理想情况下,不会有两个搜索键被转换为同一个数组索引,但是情况并不总是这样,对于未知的数据就不能做出这样的保证。因此算法的第二部分是碰撞解决。碰撞解决的两种常见方法是拉链法和开放寻址法。

Separate chaining

拉链法中,每个搜索数组索引都构建键值对链表。碰撞项通过一个单链表链接在一起,遍历链表并使用唯一的搜索键去访问目标项。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如果元素在数值上或词法上可比,保持顺序插入链表能更快的终止不成功的查找。

Other data structures for separate chaining

如果键是有序的,使用 “self-organizing” 概念例如 self-balance binary search tree 会更有效率,理论上最差情况能降为 O(lgn),虽然这引入了额外的复杂度。

dynamic perfect hashing 中,使用两层哈希表以使查询复杂度在最坏情况下降为 O(1),k 个条目的 buckets 使用 k 平方个 slots 被组织为 perfect hash table 提供最坏情况下常量的查询时间,和低平摊插入时间。

对每个 bucket 使用 fusion tree 等技术也会导致很高概率下所有操作的时间为常量。

Caching and locality of reference
Open addressing

Open addressing 是另一种碰撞解决技术,其中每个条目都存储在 bucket 数组本身中。当需要插入条目时,从哈希到的 slot 开始,使用某种序列进行探测,直到出现一个未被占用的 slot。当查询某一条目时,使用相同的序列从哈希到的 slot 开始进行查询,直到找到目标条目或者找到一个未被占用的 slot,表示查找失败。

熟知的探测序列包括:

  • Linear probing,探测的间隔是固定的 (通常为 1)。
  • Quadratic probing,探测间隔通过将二次多项式的连续输出与原始哈希计算给出的值相加来增加。
  • Double hashing,探测间隔由第二个哈希函数计算。
    在这里插入图片描述
    与单独链接相比,开放寻址的性能可能较慢,因为当负载因子趋于1时,探针序列会增加。在表完全填满的情况下,如果负载因子达到1,探测结果将是一个无限循环。线性探测的平均代价取决于哈希函数在整个表中均匀分布元素避免聚集的能力,因为聚集将导致搜索时间增加。
Caching and locality of reference

Dynamic resizing

重复的插入导致哈希表中条目的增长,使得负载因子增长。为了保证查询和插入操作的性能维持在分摊 O(1) 水平,哈希表被动态调整大小,表中的条目被重新哈希到新的哈希表中的 buckets 中。如果哈希表在删除条目后变的过空,可能会执行大小调整以避免过度的内存使用。

Resizing by moving all entries

通常,大小翻倍的新的哈希表被私有地分配,原始哈希表中的条目计算新的哈希值然后执行插入操作,以移动的新分配的哈希表中。重新哈希虽然简单,但计算成本高。

Alternatives to all-at-once rehashing
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值