数据结构与算法之数据结构 哈希表 开放寻址 / 链地址法 冲突处理

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


摘要:

哈希表是一种基于哈希函数的数据结构,它能够高效地存储和检索数据。由于哈希函数的特性,哈希表在存储过程中可能会出现冲突,即不同的键映射到同一个哈希地址。本文将围绕哈希表的冲突处理策略,分别介绍开放寻址法和链地址法,并分析它们的优缺点。

一、

哈希表是一种基于哈希函数的数据结构,它通过将键映射到哈希地址来存储和检索数据。哈希表具有查找效率高、存储空间利用率高等优点,被广泛应用于各种场景。由于哈希函数的特性,哈希表在存储过程中可能会出现冲突,即不同的键映射到同一个哈希地址。为了解决冲突,我们需要采用合适的冲突处理策略。

二、开放寻址法

开放寻址法是一种解决哈希表冲突的策略,它将所有元素存储在同一个数组中。当发生冲突时,按照某种规则在数组中寻找下一个空位,将冲突元素插入到该位置。

1. 线性探测法

线性探测法是最简单的开放寻址法。当发生冲突时,从冲突位置开始,依次向后查找,直到找到空位为止。如果数组已满,则从头开始查找。

python

class HashTableLinearProbing:


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


2. 二次探测法

二次探测法是对线性探测法的一种改进。当发生冲突时,从冲突位置开始,按照二次方程的规律查找下一个空位。

python

class HashTableQuadraticProbing:


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. 双重散列法

双重散列法是对二次探测法的一种改进。它使用两个不同的哈希函数,当发生冲突时,按照这两个哈希函数的规律查找下一个空位。

python

class HashTableDoubleHashing:


def __init__(self, size):


self.size = size


self.table = [None] self.size

def hash1(self, key):


return key % self.size

def hash2(self, key):


return 1 + (key % (self.size - 1))

def insert(self, key):


index = self.hash1(key)


i = 1


while self.table[index] is not None:


index = (index + i self.hash2(key)) % self.size


i += 1


self.table[index] = key

def search(self, key):


index = self.hash1(key)


i = 1


while self.table[index] is not None:


if self.table[index] == key:


return index


index = (index + i self.hash2(key)) % self.size


i += 1


return -1

def delete(self, key):


index = self.hash1(key)


i = 1


while self.table[index] is not None:


if self.table[index] == key:


self.table[index] = None


return


index = (index + i self.hash2(key)) % self.size


i += 1


三、链地址法

链地址法是一种解决哈希表冲突的策略,它将所有具有相同哈希地址的元素存储在同一个链表中。每个链表节点包含一个键和一个指向下一个节点的指针。

python

class HashTableChaining:


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)


if self.table[index] is None:


self.table[index] = []


self.table[index].append(key)

def search(self, key):


index = self.hash(key)


if self.table[index] is not None:


for k in self.table[index]:


if k == key:


return index


return -1

def delete(self, key):


index = self.hash(key)


if self.table[index] is not None:


for i, k in enumerate(self.table[index]):


if k == key:


del self.table[index][i]


return


四、总结

本文介绍了哈希表的两种冲突处理策略:开放寻址法和链地址法。开放寻址法将所有元素存储在同一个数组中,而链地址法将具有相同哈希地址的元素存储在同一个链表中。两种方法各有优缺点,在实际应用中需要根据具体场景选择合适的策略。

开放寻址法具有以下优点:

1. 空间利用率高,不需要额外的存储空间。

2. 查找效率高,时间复杂度为O(1)。

开放寻址法具有以下缺点:

1. 冲突概率较高,可能导致查找效率降低。

2. 删除操作较为复杂,需要移动后续元素。

链地址法具有以下优点:

1. 冲突概率较低,查找效率较高。

2. 删除操作简单,只需删除对应节点。

链地址法具有以下缺点:

1. 空间利用率较低,需要额外的存储空间。

2. 查找效率受链表长度影响,时间复杂度为O(n)。

在实际应用中,我们可以根据具体场景选择合适的冲突处理策略。例如,当哈希表大小较小且冲突概率较低时,可以选择开放寻址法;当哈希表大小较大且冲突概率较高时,可以选择链地址法。