数据结构与算法之散列表 开放寻址 线性探测 / 二次探测 深度解析

数据结构与算法阿木 发布于 3 天前 1 次阅读


摘要:

散列表(Hash Table)是一种基于散列函数将键映射到表中的位置的数据结构,它提供了快速的查找、插入和删除操作。开放寻址法是散列表的一种实现方式,其中所有元素存储在同一个数组中。本文将深入解析开放寻址法中的两种常见策略:线性探测和二次探测。

一、

散列表是一种非常高效的数据结构,它通过散列函数将键映射到数组中的一个位置,从而实现快速的查找、插入和删除操作。开放寻址法是散列表的一种实现方式,它将所有元素存储在同一个数组中。本文将重点介绍线性探测和二次探测这两种开放寻址策略。

二、线性探测

线性探测是最简单的开放寻址策略。当散列函数计算出的索引位置已经被占用时,线性探测会从该位置开始,依次向后探测,直到找到一个空位为止。

1. 线性探测的原理

线性探测的基本思想是,如果散列函数计算出的索引位置已经被占用,则向后移动一个位置继续探测。如果数组长度为m,则探测序列为:

h(k) -> h(k) + 1 -> h(k) + 2 -> ... -> h(k) + m - 1 -> h(k) + 0

2. 线性探测的代码实现

python

class LinearProbingHashTable:


def __init__(self, size):


self.size = size


self.table = [None] self.size

def hash(self, key):


return key % self.size

def insert(self, key):


index = self.hash(key)


while self.table[index] is not None:


index = (index + 1) % self.size


self.table[index] = key

def search(self, key):


index = self.hash(key)


while self.table[index] is not None:


if self.table[index] == key:


return index


index = (index + 1) % self.size


return -1

def delete(self, key):


index = self.hash(key)


while self.table[index] is not None:


if self.table[index] == key:


self.table[index] = None


return


index = (index + 1) % self.size


3. 线性探测的优缺点

优点:

- 实现简单,易于理解。

- 当散列函数设计得较好时,线性探测的性能接近O(1)。

缺点:

- 空间利用率较低,因为探测过程中可能会出现多个元素占据同一个位置。

- 当散列表接近满载时,性能会急剧下降,出现所谓的“聚集”现象。

三、二次探测

二次探测是线性探测的一种改进策略。当散列函数计算出的索引位置已经被占用时,二次探测会按照一个二次多项式的形式进行探测。

1. 二次探测的原理

二次探测的基本思想是,如果散列函数计算出的索引位置已经被占用,则向后移动一个二次多项式的位置继续探测。探测序列为:

h(k) -> h(k) + 1 -> h(k) + 4 -> h(k) + 9 -> ... -> h(k) + i^2

2. 二次探测的代码实现

python

class QuadraticProbingHashTable:


def __init__(self, size):


self.size = size


self.table = [None] self.size

def hash(self, key):


return key % self.size

def insert(self, key):


index = self.hash(key)


i = 1


while self.table[index] is not None:


index = (index + i2) % self.size


i += 1


self.table[index] = key

def search(self, key):


index = self.hash(key)


i = 1


while self.table[index] is not None:


if self.table[index] == key:


return index


index = (index + i2) % self.size


i += 1


return -1

def delete(self, key):


index = self.hash(key)


i = 1


while self.table[index] is not None:


if self.table[index] == key:


self.table[index] = None


return


index = (index + i2) % self.size


i += 1


3. 二次探测的优缺点

优点:

- 相比线性探测,二次探测可以减少聚集现象。

- 当散列函数设计得较好时,性能接近O(1)。

缺点:

- 实现相对复杂。

- 当散列表接近满载时,性能仍然会下降。

四、总结

开放寻址法是散列表的一种实现方式,其中线性探测和二次探测是两种常见的开放寻址策略。线性探测实现简单,但空间利用率低,容易产生聚集现象;二次探测可以减少聚集现象,但实现相对复杂。在实际应用中,应根据具体需求和散列函数的特点选择合适的开放寻址策略。