1. 题目
不使用任何内建的哈希表库设计一个哈希映射(HashMap
)。
实现 MyHashMap
类:
MyHashMap()
用空映射初始化对象;void put(int key, int value)
向HashMap
插入一个键值对(key, value)
。如果key
已经存在于映射中,则更新其对应的值value
;int get(int key)
返回特定的key
所映射的value
;如果映射中不包含key
的映射,返回 − 1 -1 −1 。
void remove(key)
如果映射中存在key
的映射,则移除key
和它所对应的value
。
1.1 示例
输入:
["MyHashMap", "put", "put", "get", "get", "put", "get", "remove", "get"]
[[], [1, 1], [2, 2], [1], [3], [2, 1], [2], [2], [2]]
输出:
[null, null, null, 1, -1, null, 1, null, -1]
解释:
MyHashMap myHashMap = new MyHashMap();
myHashMap.put(1, 1); // myHashMap 现在为 [[1,1]]
myHashMap.put(2, 2); // myHashMap 现在为 [[1,1], [2,2]]
myHashMap.get(1); // 返回 1 ,myHashMap 现在为 [[1,1], [2,2]]
myHashMap.get(3); // 返回 -1(未找到),myHashMap 现在为 [[1,1], [2,2]]
myHashMap.put(2, 1); // myHashMap 现在为 [[1,1], [2,1]](更新已有的值)
myHashMap.get(2); // 返回 1 ,myHashMap 现在为 [[1,1], [2,1]]
myHashMap.remove(2); // 删除键为 2 的数据,myHashMap 现在为 [[1,1]]
myHashMap.get(2); // 返回 -1(未找到),myHashMap 现在为 [[1,1]]
1.2 说明
- 来源: 力扣(LeetCode)
- 链接: https://leetcode-cn.com/problems/design-hashmap
1.3 限制
0 <= key, value <= 106
- 最多调用
1
0
4
10^4
104 次
put
、get
和remove
方法
2. 解法一(分离链接法)
2.1 分析
详细分析请参考:【数据结构Python描述】仿照Python解释器使用哈希表手动实现一个字典
下面首先使用列表作为每个 bucket
发生哈希碰撞时所使用的二级容器。
2.2 解答
from random import randrange
class MyHashMap:
class _Item:
__slots__ = 'key', 'value'
def __init__(self, key, value):
self.key = key
self.value = value
def __init__(self, cap=6500, p=109345121):
"""创建一个空的映射"""
self._table = cap * [[]]
self._n = 0
self._prime = p # MAD压缩函数中大于哈希表容量的大质数
self._scale = 1 + randrange(p-1) # MAD压缩函数中的缩放系数a
self._shift = randrange(p) # MAD压缩函数中的偏移系数b
def _hash_function(self, key):
"""哈希函数"""
return (self._scale * hash(key) + self._shift) % self._prime % len(self._table)
def __len__(self):
return self._n
def get(self, key):
j = self._hash_function(key)
bucket = self._table[j]
for item in bucket:
if item.key == key:
return item.value
return -1
def put(self, key, value):
j = self._hash_function(key)
size = len(self._table[j])
for item in self._table[j]: # 遍历查询映射中是否存在键key
if key == item.key:
item.value = value
return
self._table[j].append(self._Item(key, value)) # 映射中不存在键key
if len(self._table[j]) > size: # k为新的键
self._n += 1
if self._n > len(self._table) // 2: # 确保负载系数小于0.5
self._resize(2 * len(self._table) - 1) # 通常2 * n - 1为质数
def remove(self, key):
j = self._hash_function(key)
bucket = self._table[j]
for item in bucket: # 遍历查询映射中是否存在键key
if key == item.key:
bucket.remove(item)
self._n -= 1
return
def _resize(self, cap):
"""将哈希表容量调整为cap"""
old = list(self) # 通过迭代获得已有的所有键值对
self._table = cap * [[]]
self._n = 0
for key, value in old:
self.put(key, value)
def __iter__(self):
for bucket in self._table:
if bucket is not None:
for item in bucket:
yield item.key, item.value
下面使用链表作为每个 bucket
发生哈希碰撞时所使用的二级容器。
from random import randrange
class _ListNode:
def __init__(self, key=0, value=0, next=None):
self.key = key
self.value = value
self.next = next
class _LinkedList:
def __init__(self):
self.head = None
self.tail = None
self.n = 0
def append(self, key: int, value: int):
node = _ListNode(key, value)
if self.head is None:
self.head = node
self.tail = node
else:
self.tail.next = node
self.tail = self.tail.next
self.n += 1
def remove(self, key: int):
dummy = _ListNode()
dummy.next = self.head
predecessor, cursor = dummy, dummy.next
while cursor:
if cursor.key == key:
predecessor.next = cursor.next
self.n -= 1
self.head = dummy.next
return
predecessor, cursor = cursor, cursor.next
raise KeyError('Key does not exist!')
def __len__(self):
return self.n
class MyHashMap:
def __init__(self, cap=11, p=109345121):
"""创建一个空的映射"""
self._table = [_LinkedList() for _ in range(cap)]
self._n = 0
self._prime = p # MAD压缩函数中大于哈希表容量的大质数
self._scale = 1 + randrange(p - 1) # MAD压缩函数中的缩放系数a
self._shift = randrange(p) # MAD压缩函数中的偏移系数b
def _hash_function(self, key):
"""哈希函数"""
return (self._scale * hash(key) + self._shift) % self._prime % len(self._table)
def __len__(self):
return self._n
def get(self, key):
j = self._hash_function(key)
bucket = self._table[j]
cursor = bucket.head
while cursor:
if cursor.key == key:
return cursor.value
cursor = cursor.next
return -1
def put(self, key, value):
j = self._hash_function(key)
size = len(self._table[j])
bucket = self._table[j]
cursor = bucket.head
while cursor:
if cursor.key == key:
cursor.value = value
return
cursor = cursor.next
self._table[j].append(key, value) # 映射中不存在键key
if len(self._table[j]) > size: # k为新的键
self._n += 1
if self._n > len(self._table) // 2: # 确保负载系数小于0.5
self._resize(2 * len(self._table) - 1) # 通常2 * n - 1为质数
def remove(self, key):
j = self._hash_function(key)
bucket = self._table[j]
try:
bucket.remove(key)
self._n -= 1
return
except KeyError:
return
def _resize(self, cap):
"""将哈希表容量调整为cap"""
old = list(self) # 通过迭代获得已有的所有键值对
self._table = [_LinkedList() for _ in range(cap)]
self._n = 0
for key, value in old:
self.put(key, value)
def __iter__(self):
for bucket in self._table:
cursor = bucket.head
while cursor:
yield cursor.key, cursor.value
cursor = cursor.next
def main():
hash_map = MyHashMap()
# hash_map.put(1, 1)
# hash_map.put(2, 2)
# print(hash_map.get(1))
# print(hash_map.get(3))
# hash_map.put(2, 1)
# print(hash_map.get(2))
# hash_map.remove(2)
# print(hash_map.get(2))
operations = ["MyHashMap", "put", "put", "put", "put", "remove", "put", "put", "put", "put", "put", "put", "get",
"put", "get", "put", "remove", "get", "put", "put", "put", "put", "get", "remove", "get", "remove",
"get", "put", "put", "put", "put", "put", "put", "remove", "remove", "put", "put", "remove", "get",
"put", "put", "put", "remove", "put", "get", "put", "get", "put", "remove", "put", "put", "get",
"remove", "put", "put", "remove", "put", "put", "put", "put", "put", "remove", "put", "remove", "put",
"put", "put", "put", "remove", "put", "get", "remove", "put", "put", "put", "put", "put", "put",
"put", "put", "remove", "remove", "put", "put", "put", "get", "put", "put", "put", "remove", "remove",
"put", "put", "remove", "remove", "put", "put", "put", "remove", "remove", "put", "put", "put", "put",
"put", "put", "remove", "get", "put", "get", "get", "put", "put", "remove", "put", "get", "put",
"get", "put", "put", "put", "put", "put", "remove", "put", "remove", "put", "put", "put", "get",
"put", "put", "put", "put", "put", "put", "put", "get", "put", "put", "put", "put", "put", "remove",
"remove", "remove", "put", "put", "put", "put", "put", "get", "put", "put", "put", "get", "get",
"remove", "put", "put", "put", "put", "remove", "get", "get", "put", "put", "get", "remove", "get",
"put", "put", "put", "remove", "put", "get", "put", "get", "put", "put", "put", "remove", "put",
"remove", "put", "put", "put", "put", "remove", "put", "put", "put", "put", "remove", "put", "put",
"put", "put", "put", "put", "put", "remove", "remove", "remove", "put", "put", "put", "get", "put",
"put", "put", "put", "remove", "get", "put", "get", "put", "put", "remove", "put", "put", "put",
"put", "put", "put", "put", "remove", "remove", "remove", "put", "remove", "get", "put", "get", "put",
"get", "put", "put", "put", "put", "put", "get", "remove", "put", "put", "put", "put", "remove",
"put", "put", "get", "put", "put", "put", "remove", "put", "put", "put", "put", "remove", "put",
"remove", "remove", "put", "put", "put", "remove", "put", "put", "put", "put", "put", "get", "put",
"get", "put", "get", "get", "put", "put", "remove", "put", "remove", "put", "put", "put", "put",
"remove", "get", "get", "remove", "put", "put", "put", "remove", "get", "get", "put", "put", "put",
"put", "put", "remove", "get", "put", "put", "put", "get", "put", "put", "remove", "put", "put",
"put", "get", "get", "put", "put", "put", "remove", "put", "get", "put", "put", "remove", "put",
"remove", "remove", "put", "put", "put", "put", "get", "put", "put", "put", "remove", "remove", "put",
"get", "put", "put", "put", "put", "put", "remove", "put", "put", "put", "get", "remove", "put",
"remove", "put", "put", "put", "remove", "put", "put", "put", "remove", "put", "remove", "put", "get",
"put", "put", "remove", "put", "put", "put", "put", "put", "put", "put", "put", "put", "put", "put",
"put", "put", "get", "put", "get", "get", "put", "get", "remove", "remove", "put", "put", "put",
"put", "put", "put", "put", "remove", "get", "put", "put", "put", "put", "put", "put", "put",
"remove", "put", "put", "put", "get", "get", "get", "put", "get", "put", "put", "get", "put", "put",
"put", "remove", "put", "put", "put", "put", "put", "remove", "put", "put", "put", "put", "get",
"put", "put", "put", "put", "remove", "put", "put", "remove", "put", "put", "remove", "get", "put",
"put", "get", "get", "get", "put", "put", "put", "get", "remove", "put", "get", "remove", "put",
"get", "put", "get", "get", "put", "remove", "put", "put", "put", "put", "remove", "put", "put",
"put", "put", "get", "put", "put", "get", "get", "put", "put", "get", "get", "put", "put", "put",
"get", "put", "put", "remove", "remove", "put", "put", "put", "remove", "remove", "put", "put", "put",
"put", "put", "put", "put", "put", "put", "put", "put", "put", "get", "put", "put", "put", "get",
"put", "put", "remove", "put", "put", "put", "put", "get", "get", "put", "put", "remove", "put",
"put", "put", "put", "put", "get", "put", "get", "get", "put", "put", "put", "put", "put", "put",
"get", "put", "remove", "put", "put", "put", "put", "put", "put", "put", "put", "put", "put", "put",
"remove", "put", "get", "put", "put", "get", "put", "get", "put", "put", "put", "put", "get",
"remove", "put", "remove", "get", "remove", "put", "put", "put", "put", "put", "get", "put", "put",
"put", "put", "get", "put", "put", "put", "remove", "put", "remove", "put", "put", "put", "put",
"get", "remove", "remove", "put", "put", "put", "put", "put", "put", "put", "put", "put", "remove",
"put", "put", "put", "put", "get", "put", "put", "remove", "put", "remove", "get", "put", "put",
"put", "get", "get", "remove", "put", "put", "remove", "put", "put", "put", "put", "put", "get",
"put", "put", "remove", "get", "get", "put", "remove", "put", "put", "get", "get", "put", "get",
"put", "remove", "put", "put", "put", "remove", "put", "put", "put", "put", "put", "put", "put",
"put", "put", "put", "put", "put", "remove", "put", "get", "put", "put", "put", "get", "get",
"remove", "put", "put", "remove", "get", "put", "get", "remove", "put", "put", "put", "put", "put",
"put", "put", "put", "put", "remove", "put", "put", "remove", "get", "get", "remove", "put", "remove",
"put", "put", "get", "put", "put", "put", "put", "get", "put", "get", "put", "remove", "put", "put",
"put", "put", "put", "put", "get", "get", "put", "put", "put", "put", "put", "get", "get", "put",
"remove", "remove", "put", "remove", "get", "get", "put", "put", "put", "remove", "remove", "get",
"get", "remove", "put", "put", "put", "get", "put", "put", "put", "put", "put", "put", "get",
"remove", "put", "put", "put", "put", "get", "put", "remove", "put", "get", "get", "get", "put",
"put", "put", "put", "put", "get", "get", "put", "put", "put", "put", "put", "put", "put", "put",
"put", "put", "put", "get", "put", "put", "get", "get", "put", "get", "put", "put", "put", "put",
"put", "put", "get", "put", "get", "put", "put", "put", "remove", "get", "get", "put", "put",
"remove", "put", "put", "put", "get", "put", "put", "get", "put", "put", "get", "put", "put", "put",
"remove", "put", "put", "remove", "put", "put", "remove", "put", "put", "put", "put", "get", "get",
"get", "put", "put", "put", "put", "get", "remove", "put", "put", "remove", "get", "get", "put",
"put", "get", "put", "get", "get", "put", "put", "put", "put", "get", "remove", "put", "put", "put",
"put", "get", "put", "put", "remove", "put", "put", "put", "put", "put", "put", "put", "get", "put",
"remove", "put", "put", "put", "put", "get", "put", "put", "put", "get", "put", "put", "put", "get",
"put", "put", "put", "put", "put", "get", "put", "put", "remove", "put", "put", "get", "put", "put",
"put", "put", "get", "put", "put", "get", "put", "get", "put", "put", "put", "put", "remove", "put",
"put", "put", "put", "put", "remove", "remove", "put", "put", "remove", "put", "put", "put", "put",
"put", "get", "remove", "get", "put", "get", "remove", "put", "get", "remove", "get", "put", "put",
"put", "put", "put", "put", "put", "put", "remove", "remove", "get", "put", "put", "remove", "put",
"put", "put", "put", "put", "put", "put", "get", "put", "put", "put", "put", "put", "put", "put",
"remove", "get", "remove", "remove", "put", "put", "get", "put", "put", "put", "put", "put", "remove",
"put", "put", "remove", "put", "put", "put", "put", "put", "put", "remove", "remove", "remove", "put",
"put", "put", "get", "put", "put", "put", "remove", "put", "put"]
parameters = [[], [970, 538], [908, 29], [395, 865], [250, 847], [836], [233, 568], [657, 790], [595, 271],
[769, 219], [55, 112], [157, 493], [920], [632, 358], [669], [506, 228], [904], [473], [461, 40],
[748, 973], [446, 544], [766, 461], [395], [211], [415], [157], [252], [252, 22], [942, 681],
[600, 988], [424, 39], [685, 482], [561, 605], [632], [461], [916, 329], [739, 735], [769], [942],
[460, 226], [183, 411], [224, 524], [769], [508, 614], [632], [254, 825], [603], [115, 667], [460],
[940, 813], [50, 629], [519], [595], [39, 913], [742, 13], [765], [163, 627], [554, 130], [255, 945],
[22, 78], [912, 390], [632], [609, 410], [956], [515, 243], [975, 871], [520, 313], [682, 538], [563],
[119, 902], [916], [766], [293, 885], [657, 665], [518, 832], [897, 489], [340, 972], [790, 24],
[637, 445], [544, 498], [115], [600], [269, 209], [734, 3], [243, 108], [233], [679, 632], [640, 55],
[288, 301], [682], [871], [922, 755], [624, 787], [776], [293], [564, 902], [32, 743], [934, 278],
[250], [389], [620, 711], [420, 623], [346, 959], [829, 832], [776, 894], [465, 769], [508], [358],
[126, 481], [255], [50], [477, 991], [973, 337], [32], [823, 283], [21], [733, 431], [583],
[735, 407], [873, 702], [578, 256], [813, 221], [669, 432], [790], [941, 945], [645], [560, 775],
[823, 772], [458, 220], [243], [947, 136], [168, 560], [946, 19], [172, 608], [624, 260], [876, 516],
[76, 334], [704], [615, 737], [110, 453], [189, 678], [746, 201], [497, 330], [632], [993], [497],
[915, 545], [329, 558], [662, 773], [208, 135], [797, 614], [640], [108, 809], [262, 401], [560, 965],
[494], [222], [922], [237, 439], [688, 796], [974, 331], [367, 470], [339], [115], [790], [658, 873],
[513, 520], [2], [76], [110], [199, 511], [674, 853], [546, 849], [430], [394, 41], [189], [443, 983],
[270], [353, 44], [959, 995], [275, 798], [910], [522, 939], [176], [520, 292], [631, 538],
[216, 551], [197, 623], [55], [452, 416], [805, 462], [884, 223], [484, 454], [126], [59, 954],
[454, 575], [500, 940], [999, 520], [211, 106], [190, 915], [995, 462], [519], [368], [734],
[549, 845], [47, 885], [609, 356], [765], [163, 520], [382, 774], [190, 545], [146, 166], [748],
[282], [357, 531], [113], [89, 489], [994, 5], [967], [972, 826], [220, 91], [296, 808], [826, 7],
[401, 910], [126, 802], [534, 781], [293], [282], [515], [29, 473], [390], [32], [265, 801], [658],
[29, 648], [678], [40, 493], [9, 809], [701, 244], [345, 542], [386, 296], [632], [89], [575, 758],
[168, 575], [286, 619], [210, 335], [546], [77, 534], [380, 885], [414], [590, 272], [924, 933],
[662, 1], [544], [349, 402], [244, 274], [907, 303], [638, 453], [339], [255, 802], [973], [130],
[266, 695], [486, 444], [557, 522], [518], [392, 750], [538, 174], [407, 337], [455, 912], [755, 278],
[242], [947, 647], [367], [657, 280], [286], [255], [307, 453], [382, 216], [609], [69, 582], [340],
[36, 792], [4, 288], [518, 878], [376, 516], [873], [211], [417], [908], [695, 90], [646, 513],
[114, 675], [924], [321], [486], [300, 87], [68, 223], [924, 665], [680, 323], [410, 97], [538],
[685], [884, 617], [496, 967], [155, 853], [367], [694, 765], [607, 567], [748], [565, 855],
[151, 633], [300, 838], [76], [163], [796, 591], [516, 514], [95, 921], [353], [445, 40], [32],
[163, 846], [697, 892], [637], [870, 672], [560], [410], [909, 414], [319, 973], [259, 144],
[423, 142], [165], [984, 652], [121, 133], [117, 13], [340], [390], [237, 305], [520], [712, 752],
[380, 7], [661, 937], [249, 9], [937, 291], [168], [501, 89], [989, 540], [736, 722], [739], [250],
[741, 270], [920], [421, 848], [917, 716], [788, 294], [520], [642, 352], [250, 775], [710, 268],
[349], [801, 427], [921], [905, 183], [69], [163, 429], [274, 863], [108], [410, 289], [578, 258],
[613, 113], [992, 527], [155, 194], [557, 696], [190, 519], [630, 59], [234, 795], [740, 324],
[270, 492], [107, 63], [705, 446], [205], [390, 676], [374], [557], [321, 754], [710], [121], [488],
[156, 679], [132, 238], [793, 469], [966, 912], [612, 691], [860, 749], [245, 736], [829], [237],
[858, 449], [655, 591], [913, 760], [977, 737], [13, 954], [189, 252], [215, 933], [168], [682, 867],
[802, 747], [710, 342], [994], [257], [288], [972, 139], [255], [637, 821], [383, 858], [685],
[146, 53], [464, 179], [98, 642], [911], [524, 259], [196, 641], [644, 843], [271, 723], [706, 285],
[205], [256, 884], [291, 722], [750, 142], [205, 50], [259], [816, 839], [123, 741], [913, 349],
[894, 577], [914], [129, 267], [242, 60], [288], [189, 30], [507, 805], [277], [227], [332, 850],
[716, 309], [493], [401], [669], [682, 330], [880, 925], [4, 287], [858], [177], [351, 217], [621],
[193], [611, 128], [183], [789, 817], [655], [658], [501, 965], [412], [334, 651], [345, 411],
[73, 9], [162, 791], [644], [330, 608], [998, 312], [96, 234], [906, 419], [221], [179, 324],
[507, 978], [632], [134], [155, 691], [92, 442], [353], [861], [714, 403], [824, 261], [814, 164],
[118], [931, 816], [39, 844], [790], [894], [980, 797], [673, 80], [109, 321], [293], [256],
[625, 277], [272, 650], [890, 666], [282, 399], [50, 95], [635, 169], [25, 749], [681, 759],
[126, 84], [229, 309], [892, 941], [505, 343], [496], [843, 820], [259, 362], [549, 86], [340],
[602, 374], [711, 73], [196], [519, 269], [785, 465], [747, 706], [449, 878], [407], [357],
[459, 357], [615, 903], [191], [86, 672], [467, 638], [406, 351], [665, 29], [416, 514], [739],
[563, 810], [190], [402], [705, 575], [91, 324], [993, 183], [902, 528], [136, 560], [866, 309],
[458], [13, 751], [999], [201, 651], [666, 246], [969, 696], [249, 255], [632, 413], [109, 432],
[866, 745], [203, 476], [72, 869], [379, 178], [955, 758], [367], [864, 228], [13], [101, 120],
[679, 497], [814], [216, 235], [401], [588, 717], [914, 836], [648, 29], [253, 926], [316], [69],
[978, 205], [963], [701], [941], [758, 489], [506, 806], [597, 467], [618, 861], [863, 454], [190],
[490, 703], [866, 151], [735, 303], [217, 552], [460], [850, 691], [554, 450], [1, 997], [424],
[603, 68], [319], [883, 877], [489, 109], [819, 400], [957, 400], [467], [601], [481], [832, 895],
[979, 52], [137, 90], [394, 540], [198, 303], [562, 223], [680, 851], [911, 399], [730, 427], [563],
[983, 9], [559, 525], [422, 86], [121, 720], [531], [151, 902], [468, 501], [39], [932, 29], [650],
[598], [131, 715], [752, 133], [119, 831], [789], [606], [941], [735, 652], [107, 448], [98],
[436, 737], [728, 947], [533, 835], [971, 356], [776, 984], [880], [939, 191], [119, 844], [168],
[733], [39], [739, 760], [940], [265, 768], [523, 176], [969], [269], [464, 948], [456], [183, 358],
[559], [211, 986], [696, 242], [427, 90], [785], [868, 968], [976, 307], [667, 619], [798, 831],
[297, 468], [802, 53], [221, 956], [319, 908], [791, 313], [56, 158], [494, 398], [387, 909], [298],
[180, 573], [839], [663, 316], [460, 628], [674, 243], [254], [922], [197], [814, 245], [560, 195],
[392], [788], [439, 556], [698], [746], [138, 331], [379, 700], [984, 296], [937, 471], [968, 888],
[220, 87], [706, 368], [430, 702], [466, 349], [441], [334, 642], [324, 670], [635], [406], [734],
[611], [954, 130], [666], [601, 106], [951, 372], [382], [64, 691], [481, 581], [91, 807], [113, 529],
[307], [129, 955], [383], [926, 412], [644], [86, 862], [879, 202], [661, 959], [849, 806],
[583, 501], [331, 825], [922], [391], [68, 504], [149, 731], [463, 64], [572, 623], [165, 760], [268],
[448], [819, 282], [586], [45], [353, 316], [589], [655], [249], [382, 367], [963, 184], [625, 538],
[932], [996], [935], [612], [788], [252, 397], [728, 935], [765, 924], [976], [784, 464], [806, 326],
[625, 866], [512, 83], [569, 768], [473, 714], [401], [683], [603, 271], [762, 849], [449, 150],
[242, 372], [285], [31, 474], [716], [653, 344], [673], [588], [813], [672, 111], [120, 299],
[353, 497], [297, 510], [619, 677], [390], [50], [185, 215], [809, 322], [749, 218], [868, 920],
[955, 207], [530, 64], [95, 906], [940, 961], [505, 893], [339, 428], [364, 122], [426], [646, 775],
[455, 542], [423], [807], [142, 73], [392], [174, 439], [575, 427], [321, 697], [9, 998], [32, 272],
[351, 496], [834], [481, 71], [760], [737, 574], [812, 451], [626, 196], [102], [648], [617],
[166, 152], [701, 720], [750], [625, 425], [335, 404], [820, 328], [240], [226, 815], [508, 265],
[785], [863, 881], [298, 263], [325], [12, 960], [439, 28], [502, 331], [114], [117, 930], [922, 65],
[456], [686, 211], [668, 478], [601], [839, 336], [737, 282], [756, 191], [581, 547], [89], [167],
[695], [272, 244], [449, 570], [688, 413], [142, 769], [382], [522], [794, 632], [714, 983], [163],
[737], [310], [771, 745], [254, 395], [551], [765, 622], [263], [751], [986, 924], [76, 585],
[548, 618], [589, 427], [785], [866], [541, 789], [58, 900], [816, 495], [324, 395], [626],
[648, 807], [280, 557], [92], [994, 295], [852, 148], [700, 192], [626, 551], [628, 937], [442, 892],
[268, 263], [536], [593, 528], [567], [164, 733], [997, 800], [583, 941], [967, 894], [737],
[825, 103], [528, 774], [485, 373], [611], [935, 118], [190, 262], [494, 836], [917], [997, 448],
[269, 659], [941, 894], [913, 554], [63, 246], [167], [235, 456], [136, 501], [309], [212, 503],
[796, 931], [337], [129, 759], [302, 276], [360, 779], [809, 918], [55], [888, 433], [535, 160], [97],
[769, 627], [762], [449, 596], [703, 27], [133, 407], [509, 67], [266], [697, 778], [903, 748],
[430, 909], [464, 626], [452, 493], [891], [293], [20, 945], [686, 88], [329], [207, 827], [202, 641],
[709, 186], [303, 451], [385, 541], [409], [201], [766], [395, 956], [971], [704], [250, 34], [354],
[766], [789], [106, 974], [652, 301], [654, 875], [109, 363], [481, 935], [361, 686], [989, 931],
[488, 673], [979], [806], [450], [509, 414], [528, 835], [673], [328, 121], [303, 406], [45, 174],
[410, 906], [42, 356], [675, 953], [882, 222], [978], [252, 396], [347, 94], [367, 754], [578, 278],
[107, 628], [73, 583], [166, 100], [162], [593], [791], [740], [697, 977], [368, 152], [971],
[918, 197], [152, 444], [995, 814], [869, 900], [335, 818], [250], [951, 948], [605, 293], [959],
[873, 243], [236, 239], [577, 636], [244, 441], [884, 904], [942, 993], [708], [581], [82],
[293, 859], [622, 486], [878, 920], [220], [493, 182], [445, 582], [392, 227], [523], [800, 270],
[404, 803]]
for operation, parameter in zip(operations, parameters):
if operation == "MyHashMap":
continue
elif operation == "put":
hash_map.put(parameter[0], parameter[1])
elif operation == "get":
print(hash_map.get(parameter[0]))
else:
hash_map.remove(parameter[0])
if __name__ == '__main__':
main()
3. 解法二(线性查找法)
3.1 分析
详细分析请参考:【数据结构Python描述】仿照Python解释器使用哈希表手动实现一个字典。
3.2 解答
from random import randrange
class MyHashMap:
class _Item:
__slots__ = 'key', 'value'
def __init__(self, key, value):
self.key = key
self.value = value
_AVAIL = object() # 哨兵标识,用于标识被键值对被删除的哈希表单元
def __init__(self, cap=11, p=109345121):
"""创建一个空的映射"""
self._table = [None for _ in range(cap)]
self._n = 0
self._prime = p # MAD压缩函数中大于哈希表容量的大质数
self._scale = 1 + randrange(p - 1) # MAD压缩函数中的缩放系数a
self._shift = randrange(p) # MAD压缩函数中的偏移系数b
def _is_available(self, j):
"""当哈希表索引为j的单元处为空或键值对被删除,则返回True"""
return self._table[j] is None or self._table[j] is MyHashMap._AVAIL
def _find_slot(self, j, key):
"""查找索引为j的哈希表单元处是否有键k
该方法的返回值为一个元组,且返回的情况如下:
- 当在索引为j的哈希表单元处找到键k,则返回(True, fisrt_avail);
- 当未在哈希表任何单元处找到键k,则返回(False, j)。
"""
first_avail = None
while True:
if self._is_available(j):
if first_avail is None:
first_avail = j
if self._table[j] is None:
return False, first_avail
elif key == self._table[j].key:
return True, j
j = (j + 1) % len(self._table)
def _hash_function(self, key):
"""哈希函数"""
return (self._scale * hash(key) + self._shift) % self._prime % len(self._table)
def __len__(self):
return self._n
def get(self, key):
j = self._hash_function(key)
found, s = self._find_slot(j, key)
if not found:
return -1
return self._table[s].value
def put(self, key, value):
j = self._hash_function(key)
found, s = self._find_slot(j, key)
if not found:
self._table[s] = self._Item(key, value)
self._n += 1
else:
self._table[s].value = value
if self._n > len(self._table) // 2: # 确保负载系数小于0.5
self._resize(2 * len(self._table) - 1) # 通常2 * n - 1为质数
def remove(self, key):
j = self._hash_function(key)
found, s = self._find_slot(j, key)
if not found:
return
self._table[s] = MyHashMap._AVAIL
self._n -= 1
def _resize(self, cap):
"""将哈希表容量调整为cap"""
old = list(self) # 通过迭代获得已有的所有键值对
self._table = [None for _ in range(cap)]
self._n = 0
for key, value in old:
self.put(key, value)
def __iter__(self):
for j in range(len(self._table)):
bucket = self._table[j]
if not self._is_available(j):
yield bucket.key, bucket.value
def main():
hash_map = MyHashMap()
hash_map.remove(14)
print(hash_map.get(4)) # -1
hash_map.put(7, 3)
hash_map.put(11, 1)
hash_map.put(12, 1)
print(hash_map.get(7)) # 3
hash_map.put(1, 19)
hash_map.put(0, 3)
hash_map.put(1, 8)
hash_map.put(2, 6)
if __name__ == '__main__':
main()