哈希算法题目:设计一个哈希映射,使用双重哈希解决冲突
字数 850 2025-12-02 21:55:21
哈希算法题目:设计一个哈希映射,使用双重哈希解决冲突
题目描述
设计一个哈希映射(HashMap),要求实现以下操作:
put(key, value): 插入键值对到哈希映射中get(key): 返回键对应的值,如果键不存在则返回-1remove(key): 删除键对应的键值对
需要满足以下要求:
- 使用固定大小的数组(不涉及动态扩容)
- 使用双重哈希(double hashing)解决哈希冲突
- 键和值都是整数(为简化问题)
- 当哈希映射已满时,put操作可以覆盖已有键或失败(本题要求覆盖)
解题过程
步骤1:理解双重哈希的基本原理
双重哈希是开放地址法的一种,使用两个哈希函数来解决冲突:
- 第一个哈希函数计算初始位置:
h1(key) = key % capacity - 第二个哈希函数计算步长:
h2(key) = 1 + (key % (capacity - 1)) - 当发生冲突时,探测序列为:
(h1(key) + i * h2(key)) % capacity(i=0,1,2,...)
这样设计可以避免线性探测的"聚集"现象,提供更好的分布性。
步骤2:设计数据结构
我们需要定义:
- 一个固定大小的数组
buckets,用于存储键值对 - 特殊标记来区分空桶和已删除的桶(因为删除操作需要特殊处理)
- 数组容量(通常选择质数以保证双重哈希能遍历所有位置)
class MyHashMap:
def __init__(self, capacity=1000003): # 选择一个质数作为容量
self.capacity = capacity
self.buckets = [None] * capacity
# None表示空桶,(-1, -1)表示已删除的桶,(key, value)表示有数据的桶
步骤3:实现双重哈希函数
def _hash1(self, key):
return key % self.capacity
def _hash2(self, key):
return 1 + (key % (self.capacity - 1)) # 保证步长不为0,且与capacity互质
步骤4:实现查找位置的辅助方法
这个方法用于找到键应该存放的位置,或确认键是否存在:
def _find_index(self, key):
"""返回键应该存放的位置索引,或键当前所在的位置"""
index = self._hash1(key)
step = self._hash2(key)
first_deleted = -1 # 记录第一个遇到的已删除位置
i = 0
while i < self.capacity:
current = self.buckets[index]
# 如果遇到空桶,说明键不存在
if current is None:
# 如果有遇到过已删除的位置,优先复用
return first_deleted if first_deleted != -1 else index
# 如果遇到已删除的桶,记录位置但继续查找
elif current == (-1, -1):
if first_deleted == -1:
first_deleted = index
# 如果找到键本身
elif current[0] == key:
return index
# 冲突,继续探测
index = (index + step) % self.capacity
i += 1
# 如果数组已满且没找到,返回第一个可用的已删除位置或最后一个探测位置
return first_deleted if first_deleted != -1 else -1
步骤5:实现put方法
def put(self, key, value):
index = self._find_index(key)
if index == -1: # 哈希表已满且没有合适位置
return
# 如果位置是已删除或空桶,或者键已存在,直接插入/覆盖
self.buckets[index] = (key, value)
步骤6:实现get方法
def get(self, key):
index = self._find_index(key)
if index == -1 or self.buckets[index] is None or self.buckets[index] == (-1, -1):
return -1
return self.buckets[index][1]
步骤7:实现remove方法
def remove(self, key):
index = self._find_index(key)
if index != -1 and self.buckets[index] is not None and self.buckets[index] != (-1, -1):
# 标记为已删除,而不是直接设为None
self.buckets[index] = (-1, -1)
步骤8:完整代码实现
class MyHashMap:
def __init__(self, capacity=1000003):
self.capacity = capacity
self.buckets = [None] * capacity
def _hash1(self, key):
return key % self.capacity
def _hash2(self, key):
return 1 + (key % (self.capacity - 1))
def _find_index(self, key):
index = self._hash1(key)
step = self._hash2(key)
first_deleted = -1
i = 0
while i < self.capacity:
current = self.buckets[index]
if current is None:
return first_deleted if first_deleted != -1 else index
elif current == (-1, -1):
if first_deleted == -1:
first_deleted = index
elif current[0] == key:
return index
index = (index + step) % self.capacity
i += 1
return first_deleted if first_deleted != -1 else -1
def put(self, key, value):
index = self._find_index(key)
if index != -1:
self.buckets[index] = (key, value)
def get(self, key):
index = self._find_index(key)
if index == -1 or self.buckets[index] is None or self.buckets[index] == (-1, -1):
return -1
return self.buckets[index][1]
def remove(self, key):
index = self._find_index(key)
if index != -1 and self.buckets[index] is not None and self.buckets[index] != (-1, -1):
self.buckets[index] = (-1, -1)
关键点总结
- 双重哈希通过两个不同的哈希函数减少冲突和聚集现象
- 删除操作使用特殊标记(-1, -1)而不是直接设为None,保证探测序列的连续性
- _find_index方法统一处理查找逻辑,避免代码重复
- 选择质数作为容量可以保证双重哈希能遍历所有位置
- 时间复杂度:平均情况下O(1),最坏情况下O(n)