Skip to content

Commit 2c4d645

Browse files
authored
Merge pull request Ehco1996#2 from Ehco1996/dev
update
2 parents 12937dd + 424f6df commit 2c4d645

File tree

13 files changed

+903
-0
lines changed

13 files changed

+903
-0
lines changed

ehco/__init__.py

Whitespace-only changes.

ehco/array_list/array_and_list.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from array import array
2+
3+
arr = array('u', 'td')
4+
5+
print(arr[0], arr[1])
6+
print(arr)
7+
8+
9+
class Array:
10+
'''定长的array'''
11+
12+
def __init__(self, size=32):
13+
self._size = size
14+
self._items = [None] * size
15+
16+
def __getitem__(self, index):
17+
return self._items[index]
18+
19+
def __setitem__(self, index, value):
20+
self._items[index] = value
21+
22+
def __len__(self):
23+
return len(self._items)
24+
25+
def clear(self, value=None):
26+
for i in range(self._items):
27+
self._items[i] = value
28+
29+
def __iter__(self):
30+
for item in self._items:
31+
yield item
32+
33+
34+
def test_array():
35+
size = 10
36+
a = Array(size)
37+
a[0] = 1
38+
assert a[0] == 1
39+
assert len(a) == 10

ehco/base/bag_adt.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
class Bag:
2+
3+
def __init__(self, max_size=10):
4+
self.max_size = max_size
5+
self._items = list()
6+
7+
def add(self, item):
8+
if len(self._items) >= self.max_size:
9+
raise Exception('Bag is Full')
10+
self._items.append(item)
11+
12+
def remove(self, item):
13+
self._items.remove(item)
14+
15+
def __len__(self):
16+
return len(self._items)
17+
18+
def __iter__(self):
19+
for item in self._items:
20+
yield item
21+
22+
23+
def test_bag():
24+
bag = Bag()
25+
26+
for i in range(10):
27+
bag.add(i)
28+
29+
bag.remove(3)
30+
assert len(bag) == 9
31+
32+
bag.add(1)
33+
assert len(bag) == 10
34+
35+
try:
36+
bag.add(1)
37+
print('len', len(bag))
38+
except Exception as e:
39+
print(e)
40+
41+
for i in bag:
42+
print(i)
43+
44+
45+
if __name__ == '__main__':
46+
test_bag()

ehco/dict/__init__.py

Whitespace-only changes.

ehco/dict/dict.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
from ehco.hashtable.hashtable_adt import HashTable
2+
3+
4+
class DictADT(HashTable):
5+
6+
def _iter_slot(self):
7+
for slot in self._table:
8+
if slot not in (HashTable.EMPTY, HashTable.UNUSED):
9+
yield slot
10+
11+
def __setitem__(self, key, value):
12+
self.add(key, value)
13+
14+
def __getitem__(self, key):
15+
if key not in self:
16+
raise KeyError()
17+
else:
18+
return self.get(key)
19+
20+
def items(self):
21+
for slot in self._iter_slot():
22+
yield (slot.key, slot.value)
23+
24+
def keys(self):
25+
for slot in self._iter_slot():
26+
yield slot.key
27+
28+
def values(self):
29+
for slot in self._iter_slot():
30+
yield slot.value
31+
32+
33+
def test_dict_adt():
34+
import random
35+
36+
d = DictADT()
37+
38+
d['a'] = 1
39+
assert d['a'] == 1
40+
d.remove('a')
41+
42+
assert len(d) == 0
43+
44+
l = list(range(30))
45+
random.shuffle(l)
46+
for i in l:
47+
d.add(i, i)
48+
49+
for i in range(30):
50+
assert d.get(i) == i
51+
52+
assert sorted(list(d.keys())) == sorted(l)

ehco/hashtable/__init__.py

Whitespace-only changes.

ehco/hashtable/hashtable_adt.py

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
class Array(object):
2+
3+
def __init__(self, size=32, init=None):
4+
self._size = size
5+
self._items = [init] * size
6+
7+
def __getitem__(self, index):
8+
return self._items[index]
9+
10+
def __setitem__(self, index, value):
11+
self._items[index] = value
12+
13+
def __len__(self):
14+
return self._size
15+
16+
def clear(self, value=None):
17+
for i in range(self._items):
18+
self._items[i] = value
19+
20+
def __iter__(self):
21+
for item in self._items:
22+
yield item
23+
24+
25+
class Slot(object):
26+
"""定义一个 hash 表 数组的槽
27+
注意,一个槽有三种状态,看你能否想明白。相比链接法解决冲突,二次探查法删除一个 key 的操作稍微复杂。
28+
29+
1.从未使用 HashMap.UNUSED。此槽没有被使用和冲突过,查找时只要找到 UNUSED 就不用再继续探查了
30+
2.使用过但是 remove 了,此时是 HashMap.EMPTY,该探查点后边的元素扔可能是有key
31+
3.槽正在使用 Slot 节点
32+
"""
33+
34+
def __init__(self, key, value):
35+
self.key, self.value = key, value
36+
37+
38+
class HashTable(object):
39+
40+
# 没有被使用过的
41+
UNUSED = None
42+
# 使用过却被删除了
43+
EMPTY = Slot(None, None)
44+
45+
def __init__(self):
46+
self._table = Array(8, init=HashTable.UNUSED)
47+
self.length = 0
48+
49+
@property
50+
def _load_factor(self):
51+
# load factor 超过0.8的时候重新分配
52+
return self.length / float(len(self._table))
53+
54+
def __len__(self):
55+
return self.length
56+
57+
def _hash(self, key):
58+
return abs(hash(key)) % len(self._table)
59+
60+
def _find_key(self, key):
61+
index = self._hash(key)
62+
_len = len(self._table)
63+
while self._table[index] is not HashTable.UNUSED:
64+
if self._table[index] is HashTable.EMPTY:
65+
index = (index * 5 + 1) % _len
66+
continue
67+
elif self._table[index].key == key:
68+
return index
69+
else:
70+
index = (index * 5 + 1) % _len
71+
return None
72+
73+
def _find_slot_for_insert(self, key):
74+
index = self._hash(key)
75+
_len = len(self._table)
76+
while not self._slot_can_insert(index):
77+
index = (index * 5 + 1) % _len
78+
return index
79+
80+
def _slot_can_insert(self, index):
81+
return self._table[index] in (HashTable.EMPTY, HashTable.UNUSED)
82+
83+
def __contains__(self, key):
84+
index = self._find_key(key)
85+
return index is not None
86+
87+
def add(self, key, value):
88+
if key in self:
89+
index = self._find_key(key)
90+
self._table[index].value = value
91+
return False
92+
else:
93+
index = self._find_slot_for_insert(key)
94+
self._table[index] = Slot(key, value)
95+
self.length += 1
96+
if self._load_factor >= 0.8:
97+
self._rehash()
98+
return True
99+
100+
def _rehash(self):
101+
old_table = self._table
102+
newsize = len(self._table) * 2
103+
self._table = Array(newsize, HashTable.UNUSED)
104+
self.length = 0
105+
106+
for slot in old_table:
107+
if slot not in (HashTable.UNUSED, HashTable.EMPTY):
108+
index = self._find_slot_for_insert(slot.key)
109+
self._table[index] = slot
110+
self.length += 1
111+
112+
def get(self, key, default=None):
113+
index = self._find_key(key)
114+
if index is None:
115+
return default
116+
else:
117+
return self._table[index].value
118+
119+
def remove(self, key):
120+
index = self._find_key(key)
121+
if index is None:
122+
raise KeyError()
123+
value = self._table[index].value
124+
self.length -= 1
125+
self._table[index] = HashTable.EMPTY
126+
return value
127+
128+
def __iter__(self):
129+
for slot in self._table:
130+
if slot not in (HashTable.EMPTY, HashTable.UNUSED):
131+
yield slot.key
132+
133+
134+
def test_hash_table():
135+
h = HashTable()
136+
137+
h.add('a', 0)
138+
h.add('b', 1)
139+
h.add('c', 2)
140+
141+
assert len(h) == 3
142+
assert h.get('a') == 0
143+
assert h.get('b') == 1
144+
assert h.get('hehe') is None
145+
146+
h.remove('a')
147+
assert h.get('a') is None
148+
assert sorted(list(h)) == ['b', 'c']
149+
150+
n = 50
151+
for i in range(n):
152+
h.add(i, i)
153+
154+
for i in range(n):
155+
assert h.get(i) == i

0 commit comments

Comments
 (0)