Skip to content

Commit 6e98745

Browse files
committed
使用二次方探查重新实现 hashtable 类
1 parent 4b08469 commit 6e98745

File tree

5 files changed

+37
-9
lines changed

5 files changed

+37
-9
lines changed

docs/7_哈希表/hashtable.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ class HashTable(object):
145145
pass
146146
```
147147

148-
具体的实现和代码编写在视频里讲解。
148+
具体的实现和代码编写在视频里讲解。这个代码可不太好实现,稍不留神就会有错,我们还是通过编写单元测试验证代码的正确性。
149149

150150
# 延伸阅读
151151
- 《Data Structures and Algorithms in Python》11 章 Hash Tables

docs/7_哈希表/hashtable.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,6 @@ def _hash1(self, key):
6060
""" 计算key的hash值"""
6161
return abs(hash(key)) % len(self._table)
6262

63-
def _hash2(self, key):
64-
""" key冲突时候用来计算新槽的位置"""
65-
return 1 + abs(hash(key)) % (len(self._table) - 2)
66-
6763
def _find_slot(self, key, for_insert=False):
6864
"""_find_slot
6965
@@ -72,21 +68,24 @@ def _find_slot(self, key, for_insert=False):
7268
:return: slot index or None
7369
"""
7470
index = self._hash1(key)
75-
step = self._hash2(key)
71+
base_index = index
72+
hash_times = 1
7673
_len = len(self._table)
7774

7875
if not for_insert: # 查找是否存在 key
7976
while self._table[index] is not HashTable.UNUSED:
8077
if self._table[index] is HashTable.EMPTY:
81-
index = (index + step) % _len
78+
index = (index + hash_times * hash_times) % _len # 一个简单的二次方探查
8279
continue
8380
elif self._table[index].key == key:
8481
return index
85-
index = (index + step) % _len
82+
index = (index + hash_times * hash_times) % _len
83+
hash_times += 1
8684
return None
8785
else:
8886
while not self._slot_can_insert(index): # 循环直到找到一个可以插入的槽
89-
index = (index + step) % _len
87+
index = (index + hash_times * hash_times) % _len
88+
hash_times += 1
9089
return index
9190

9291
def _slot_can_insert(self, index):
@@ -159,6 +158,7 @@ def test_hash_table():
159158

160159
assert sorted(list(h)) == ['b', 'c']
161160

161+
# 50 超过了 HashTable 的原始 size,我们测试下是否 reshah 操作能正确工作
162162
for i in range(50):
163163
h.add(i, i)
164164

docs/8_字典/dict.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# 字典 dict
2+
3+
上一章我们介绍了哈希表,其实 python 内置的 dict 就是用哈希表实现的,所以这一章实现 dict 就非常简单了。
4+
当然 cpython 使用的是 c 语言实现的,远比我们写的复杂得多 (cpython/Objects/dictobject.c)。
5+
上一章我们用 python 自己写的一个 Array 来代表定长数组,然后用它实现的 HashTable,它支持三个最基本的方法
6+
7+
- add(key ,value): 有 key 则更新,否则插入
8+
- get(key, default=None): 或者 key 的值,不存在返回默认值 None
9+
- remove(key): 删除一个 key,这里其实不是真删除,而是标记为 Empty
10+
11+
字典最常使用的场景就是 k,v 存储,经常用作缓存,它的 key 值是唯一的。
12+
内置库 collections.OrderDict 还保持了 key 的添加顺序,其实用我们之前实现的链表也能自己实现一个 OrderDict。
13+
14+
# 实现 dict
15+
16+
其实上边 HashTable 实现的三个基本方法就是我们使用字典最常用的三个基本方法, 这里我们继承一下这个类,
17+
然后实现更多 dict 支持的方法,items(), keys(), values()。不过需要注意的是,在 python2 和 python3 里这些方法
18+
的返回是不同的,python3 里一大改进就是不再返回浪费内存的 列表,而是返回迭代器,你要获得列表必须用 list() 转换成列表。 这里我们实现 python3 的方式返回迭代器。
19+
20+
21+
```py
22+
class DictADT(HashTable):
23+
pass
24+
```
25+
26+
视频里我们将演示如何实现这些方法,并且写单侧验证正确性。

docs/9_集合/set.md

Whitespace-only changes.

mkdocs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,5 @@ pages:
1717
- : '5_栈/stack.md'
1818
- 算法分析: '6_算法分析/big_o.md'
1919
- 哈希表: '7_哈希表/hashtable.md'
20+
- 字典: '8_字典/dict.md'
21+
- 集合: '9_集合/set.md'

0 commit comments

Comments
 (0)