📜  散列|设置 3(开放寻址)

📅  最后修改于: 2021-10-27 07:29:18             🧑  作者: Mango

我们强烈建议参考以下帖子作为此的先决条件。
散列|第一套(介绍)
散列|设置 2(单独链接)

开放寻址
与单独链接一样,开放寻址是一种处理冲突的方法。在开放寻址中,所有元素都存储在哈希表本身中。所以在任何时候,表的大小都必须大于或等于键的总数(注意,如果需要,我们可以通过复制旧数据来增加表的大小)。

Insert(k):继续探测直到找到一个空槽。找到空槽后,插入k。

Search(k):继续探测,直到槽的键不等于 k 或到达一个空槽。

Delete(k):删除操作很有趣。如果我们简单地删除一个键,那么搜索可能会失败。因此,已删除键的插槽被特别标记为“已删除”。
插入可以在已删除的插槽中插入项目,但搜索不会在已删除的插槽处停止。

开放寻址通过以下方式完成:

a) 线性探测:在线性探测中,我们线性探测下一个时隙。例如,两个探针之间的典型间隙为 1,如下例所示。
hash(x)是使用散列函数计算的槽索引, S是表大小

If slot hash(x) % S is full, then we try (hash(x) + 1) % S
If (hash(x) + 1) % S is also full, then we try (hash(x) + 2) % S
If (hash(x) + 2) % S is also full, then we try (hash(x) + 3) % S 
..................................................
..................................................

让我们考虑一个简单的散列函数作为“key mod 7”,将一个键序列作为 50, 700, 76, 85, 92, 73, 101。

开放寻址

线性探测的挑战:

  1. 主要聚类:线性探测的问题之一是主要聚类,许多连续的元素形成组,并且开始需要时间来寻找空闲槽或搜索元素。  
  2. Secondary Clustering Secondary Clustering 不那么严重,如果两个记录的初始位置相同,则它们只有相同的碰撞链(Probe Sequence)。

b) 二次探测我们在第 i 次迭代中寻找第 i 2个槽。

let hash(x) be the slot index computed using hash function.  
If slot hash(x) % S is full, then we try (hash(x) + 1*1) % S
If (hash(x) + 1*1) % S is also full, then we try (hash(x) + 2*2) % S
If (hash(x) + 2*2) % S is also full, then we try (hash(x) + 3*3) % S
..................................................
..................................................

c)双散列我们使用另一个散列函数hash2(x) 并在第 i 个循环中寻找 i*hash2(x) 槽。

let hash(x) be the slot index computed using hash function.  
If slot hash(x) % S is full, then we try (hash(x) + 1*hash2(x)) % S
If (hash(x) + 1*hash2(x)) % S is also full, then we try (hash(x) + 2*hash2(x)) % S
If (hash(x) + 2*hash2(x)) % S is also full, then we try (hash(x) + 3*hash2(x)) % S
..................................................
..................................................

有关分步图,请参见此处。

以上三者的比较:
线性探测具有最好的缓存性能,但会受到集群的影响。线性探测的另一个优点是易于计算。
二次探测在缓存性能和集群方面介于两者之间。
双散列的缓存性能很差,但没有集群。双散列需要更多的计算时间,因为需要计算两个散列函数。

S.No. Separate Chaining Open Addressing
1. Chaining is Simpler to implement. Open Addressing requires more computation.
2. In chaining, Hash table never fills up, we can always add more elements to chain. In open addressing, table may become full.
3. Chaining is Less sensitive to the hash function or load factors. Open addressing requires extra care to avoid clustering and load factor.
4. Chaining is mostly used when it is unknown how many and how frequently keys may be inserted or deleted. Open addressing is used when the frequency and number of keys is known.
5. Cache performance of chaining is not good as keys are stored using linked list. Open addressing provides better cache performance as everything is stored in the same table.
6. Wastage of Space (Some Parts of hash table in chaining are never used). In Open addressing, a slot can be used even if an input doesn’t map to it.
7. Chaining uses extra space for links. No links in Open addressing

开放寻址的性能:
与 Chaining 一样,可以在假设每个键同样可能被散列到表的任何槽的情况下评估散列的性能(简单的统一散列)

m = Number of slots in the hash table
n = Number of keys to be inserted in the hash table
 
Load factor α = n/m  ( < 1 )

Expected time to search/insert/delete < 1/(1 - α) 

So Search, Insert and Delete take (1/(1 - α)) time

?list=PLqM7alHXFySGwXaessYMemAnITqlZdZVE
参考:
http://courses.csail.mit.edu/6.006/fall11/lectures/lecture10.pdf
https://www.cse.cuhk.edu.hk/irwin.king/_media/teaching/csc2100b/tu6.pdf

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程