python 实现哈希表(数组自己实现,二次探查)
1 class Array(object): 2 3 def __init__(self, size = 32, init = None): 4 self._size = size 5 self._items = [init] * size 6 7 8 def __getitem__(self, index): 9 return self._items[index] 10 11 12 def __setitem__(self, index, value): 13 self._items[index] = value 14 15 16 def __len__(self): 17 return self._size 18 19 20 def clear(self, value = None): 21 for i in range(self,_items): 22 self._items[i] = value 23 24 25 def __iter__(self): 26 for item in self._items: 27 yield item 28 29 30 31 32 class Slot(object): 33 """ 34 定义一个哈希表数组的槽 35 注意:一个槽有三种状态 36 1. 从未被使用过,HashMap.UNUSED。 此槽没有被使用和冲突过,查找时只要找到UNUSED 就不用再继续探查了 37 2. 使用过但是remove了, 此时是HashMap.EMPTY,该谈差点后面的元素仍可能是有key 38 3. 槽正在使用Slot 节点 39 """ 40 def __init__(self, key, value): 41 self.key = key 42 self.value = value 43 44 45 class HashTable(object): 46 UNUSED = None # 表示slot 没有被使用过 47 EMPTY = Slot(None, None) # 使用过被删除 48 49 50 def __init__(self): 51 self._table = Array(8, init = HashTable.UNUSED) # 初始化,数组的每个元素都是UNUSED 52 self.length = 0 53 54 55 @property # 内置装饰器,把方法变成属性 56 def _load_factor(self): 57 return self.length/float(len(self._table)) 58 59 60 def __len__(self): 61 return self.length 62 63 64 def _hash(self, key): 65 return abs(hash(key)) % len(self._table) # abs函数返回绝对值 hash 是内置函数 _hash 直接使用内置的哈希函数,对数组的长度取模 66 67 68 def _find_key(self, key): 69 index = self._hash(key) # 先用 _hash方法计算出槽的位置 70 _len = len(self._table) # 现保存下来长度 71 while self._table[index] is not HashTable.UNUSED: # 如果这个槽不是没有被使用过 72 if self._table[index] is HashTable.EMPTY: # 如果这个槽是,曾经有过值,不过被删除了 73 index = (index*5 +1 ) % _len # cpython 使用的一种解决哈希冲突的方式 74 continue 75 elif self._table[index].key == key: # 正在使用, 如果key值相同 76 return index 77 else: # 这里就只剩最后一种可能, 正在使用,但是key没有找到 78 index = (index *5 +1) % _len 79 return None 80 81 82 def _slot_can_insert(self, index): # 判断一个槽是否可以插入 83 return (self._table[index] is HashTable.EMPTY or self._table[index] is HashTable.UNUSED) 84 85 86 def _find_slot_for_insert(self,key): # 寻找一个空槽,用来插入 87 index = self._hash(key) 88 _len = len(self._table) 89 while not self._slot_can_insert(index): 90 index = (index*5 + 1) % _len 91 return index 92 93 94 def __contains__(self, key): # 实现一个in操作符 95 index = self._find_key(key) 96 return index is not None 97 98 99 def add(self, key, value): 100 if key in self: # 上面实现的in操作符 101 index = self._find_key(key) 102 self._table[index].value = value 103 return False # 返回False 表示没有执行插入操作,执行的是更新操作 104 else: 105 index = self._find_slot_for_insert(key) 106 self._table[index] = Slot(key, value) # 这两部可能会调用_slot_can_insert 函数,不管是哪种情况,EMPTY 或 是 UNUSEZD,都将这个节点声明为Slot类 107 self.length += 1 108 if self._load_factor >= 0.8: 109 self._rehash() # 当空间占用大于0.8 的时候,进行rehash 重新分配空间。 110 return True 111 112 def _rehash(self): 113 old_table = self._table 114 newsize = len(self._table) *2 115 self._table = Array(newsize, HashTable.UNUSED) 116 self.length = 0 117 118 for slot in old_table: 119 if slot is not HashTable.UNUSED and slot is not HashTable.EMPTY: # 判断这个slot 是有值的 120 index = self._find_slot_for_insert(slot.key) # 找到一个可以插入的槽 121 self._table[index] = slot 122 self.length += 1 123 124 125 def get(self, key, default = None): 126 index = self._find_key(key) 127 if index is None: 128 return default 129 else: 130 return self._table[index].value 131 132 133 def remove(self,key): 134 index = self._find_key(key) 135 if index is None: 136 raise KeyError() 137 value = self._table[index].value 138 self.length -= 1 139 self._table[index] = HashTable.EMPTY 140 return value 141 142 143 def __iter__(self): # 遍历操作,python 字典默认遍历的是key,这里实现的也是遍历key 144 for slot in self._table: 145 if slot not in(HashTable.EMPTY, HashTable.UNUSED): 146 yield slot.key 147 148 149 150 def test_hash_table(): 151 h = HashTable() 152 h.add('a', 0) 153 h.add('b', 1) 154 h.add('c', 2) 155 assert len(h) == 3 156 assert h.get('a') ==0 157 assert h.get('b') ==1 158 assert h.get('c') ==2 159 assert h.get('gsdg') == None 160 161 h.remove('a') 162 assert h.get('a') == None 163 assert sorted(list(h)) == ['b','c'] 164 165 166 for n in range(50): 167 h.add(n,n) 168 169 for n in range(50): 170 h.get(n) == n
分类:
数据结构
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix