Skip to content

Commit 88381fe

Browse files
committed
initial commit
0 parents  commit 88381fe

File tree

4 files changed

+524
-0
lines changed

4 files changed

+524
-0
lines changed

.gitignore

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
6+
# C extensions
7+
*.so
8+
9+
# Distribution / packaging
10+
.Python
11+
build/
12+
develop-eggs/
13+
dist/
14+
downloads/
15+
eggs/
16+
.eggs/
17+
lib/
18+
lib64/
19+
parts/
20+
sdist/
21+
var/
22+
wheels/
23+
pip-wheel-metadata/
24+
share/python-wheels/
25+
*.egg-info/
26+
.installed.cfg
27+
*.egg
28+
MANIFEST
29+
30+
# PyInstaller
31+
# Usually these files are written by a python script from a template
32+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
33+
*.manifest
34+
*.spec
35+
36+
# Installer logs
37+
pip-log.txt
38+
pip-delete-this-directory.txt
39+
40+
# Unit test / coverage reports
41+
htmlcov/
42+
.tox/
43+
.nox/
44+
.coverage
45+
.coverage.*
46+
.cache
47+
nosetests.xml
48+
coverage.xml
49+
*.cover
50+
*.py,cover
51+
.hypothesis/
52+
.pytest_cache/
53+
cover/
54+
55+
# Translations
56+
*.mo
57+
*.pot
58+
59+
# Django stuff:
60+
*.log
61+
local_settings.py
62+
db.sqlite3
63+
db.sqlite3-journal
64+
65+
# Flask stuff:
66+
instance/
67+
.webassets-cache
68+
69+
# Scrapy stuff:
70+
.scrapy
71+
72+
# Sphinx documentation
73+
docs/_build/
74+
75+
# PyBuilder
76+
.pybuilder/
77+
target/
78+
79+
# Jupyter Notebook
80+
.ipynb_checkpoints
81+
82+
# IPython
83+
profile_default/
84+
ipython_config.py
85+
86+
# pyenv
87+
# For a library or package, you might want to ignore these files since the code is
88+
# intended to run in multiple environments; otherwise, check them in:
89+
# .python-version
90+
91+
# pipenv
92+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
93+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
94+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
95+
# install all needed dependencies.
96+
#Pipfile.lock
97+
98+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
99+
__pypackages__/
100+
101+
# Celery stuff
102+
celerybeat-schedule
103+
celerybeat.pid
104+
105+
# SageMath parsed files
106+
*.sage.py
107+
108+
# Environments
109+
.env
110+
.venv
111+
env/
112+
venv/
113+
ENV/
114+
env.bak/
115+
venv.bak/
116+
117+
# Spyder project settings
118+
.spyderproject
119+
.spyproject
120+
121+
# Rope project settings
122+
.ropeproject
123+
124+
# mkdocs documentation
125+
/site
126+
127+
# mypy
128+
.mypy_cache/
129+
.dmypy.json
130+
dmypy.json
131+
132+
# Pyre type checker
133+
.pyre/
134+
135+
# pytype static type analyzer
136+
.pytype/
137+
138+
# Cython debug symbols
139+
cython_debug/
140+
141+
# static files generated from Django application using `collectstatic`
142+
media
143+
static

binarytree.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#!/usr/bin/env python
2+
3+
4+
class AlreadyExistsError(Exception):
5+
pass
6+
7+
8+
class BinaryTree:
9+
def __init__(self, value, left=None, right=None):
10+
self._value = value
11+
self._left = left
12+
self._right = right
13+
14+
def __contains__(self, value):
15+
if value < self._value:
16+
return self._left and value in self._left
17+
if value > self._value:
18+
return self._right and value in self._right
19+
return True
20+
21+
def __repr__(self):
22+
res = ""
23+
if self._left:
24+
res += str(self._left) + ", "
25+
res += str(self._value)
26+
if self._right:
27+
res += ", " + str(self._right)
28+
return res
29+
30+
def __iter__(self):
31+
return self
32+
33+
def __next__(self):
34+
if self._left:
35+
yield from self._left
36+
yield self._value
37+
if self._right:
38+
yield from self._right
39+
raise StopIteration
40+
41+
def insert(self, value):
42+
if self._value == value:
43+
raise AlreadyExistsError
44+
if value < self._value:
45+
if not self._left:
46+
self._left = BinaryTree(value)
47+
elif self._left._value < value:
48+
tmp = self._left
49+
self._left = BinaryTree(value, left=tmp)
50+
else:
51+
self._left.insert(value)
52+
if value > self._value:
53+
if not self._right:
54+
self._right = BinaryTree(value)
55+
elif self._right._value > value:
56+
tmp = self._right
57+
self._right = BinaryTree(value, right=tmp)
58+
else:
59+
self._right.insert(value)
60+
61+
def remove(self, value):
62+
pass
63+
64+
65+
if __name__ == "__main__":
66+
bt = BinaryTree(5)
67+
# insert
68+
bt.insert(9)
69+
bt.insert(3)
70+
bt.insert(7)
71+
bt.insert(2)
72+
bt.insert(6)
73+
bt.insert(4)
74+
bt.insert(8)
75+
bt.insert(1)
76+
bt.insert(0)
77+
witness = list(range(10))
78+
assert list(bt) == witness

hashmap.py

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
#!/usr/bin/env python
2+
3+
from linkedlist import LinkedList
4+
5+
6+
class HashMap:
7+
def __init__(self, **kwargs):
8+
self._occupied = self._old_occupied = 0
9+
self._size = 2
10+
self._store = [None] * self._size
11+
self._load_factor = 0.75
12+
self._resizing = False
13+
14+
# used to increase capacity
15+
self._old_size = None
16+
self._old_store = None
17+
# how many to transfer at a time
18+
self._resize_factor = 5
19+
20+
for (k, v) in kwargs:
21+
self[k] = v
22+
23+
def __getitem__(self, key):
24+
def lookup(store, size):
25+
index = hash(key) % size
26+
for (k, v) in store[index]:
27+
if key == k:
28+
return v
29+
30+
if value := lookup(self._store, self._size):
31+
return value
32+
if value := lookup(self._old_store, self._old_size):
33+
return value
34+
raise KeyError
35+
36+
def __setitem__(self, key, value, transfer=False):
37+
if (
38+
self._occupied >= self._load_factor * self._size
39+
and not self._resizing # already resizing
40+
and not transfer # during transfer
41+
):
42+
# resizing:
43+
self._occupied = 0
44+
# - copy the actual store
45+
self._old_store = self._store
46+
self._old_size = self._size
47+
# - allocate a bigger one
48+
self._size *= 2
49+
self._store = [None] * self._size
50+
# - start transfering
51+
self._resizing = True
52+
53+
if not transfer:
54+
self._transfer()
55+
56+
self._occupied += 1
57+
index = hash(key) % self._size
58+
if self._store[index]:
59+
for (k, v) in self._store[index]:
60+
if k == key:
61+
self._store[index].remove((k, v))
62+
self._store[index].append((key, value))
63+
else:
64+
self._store[index] = LinkedList((key, value))
65+
66+
def __delitem__(self, key):
67+
def rm(store, size):
68+
try:
69+
index = hash(key) % size
70+
if not store[index]:
71+
return
72+
for (k, v) in store[index]:
73+
if k == key:
74+
store[index].remove((k, v))
75+
except ValueError:
76+
raise IndexError
77+
78+
if self._resizing:
79+
rm(self._old_store, self._old_size)
80+
rm(self._store, self._size)
81+
self._occupied -= 1
82+
83+
def __iter__(self):
84+
# TODO
85+
return self
86+
87+
def __repr__(self):
88+
values = []
89+
if self._resizing:
90+
for ll in filter(bool, self._old_store):
91+
values += [f"{k}: {v}" for (k, v) in ll]
92+
for ll in filter(bool, self._store):
93+
values += [f"{k}: {v}" for (k, v) in ll]
94+
values = map(str, values)
95+
return "{" + ", ".join(values) + "}"
96+
97+
def __contains__(self, key):
98+
def search(store):
99+
for ll in filter(bool, store):
100+
for (k, v) in ll:
101+
if k == key:
102+
return True
103+
104+
return (self._old_store and search(self._old_store)) or search(self._store)
105+
106+
def _transfer(self):
107+
if not self._resizing:
108+
return
109+
remaining = self._resize_factor
110+
for index, ll in enumerate(filter(bool, self._old_store)):
111+
if remaining == 0:
112+
return
113+
remaining -= 1
114+
self._old_store[index] = None
115+
for (k, v) in ll:
116+
self._occupied += 1
117+
index = hash(k)
118+
self.__setitem__(k, v, transfer=True)
119+
else:
120+
# all None, we're done transfering
121+
self._resizing = False
122+
self._old_store = None
123+
self._old_size = 0
124+
125+
126+
if __name__ == "__main__":
127+
hm = HashMap()
128+
# add
129+
for i in range(7):
130+
hm[i] = i
131+
witness = {i: i for i in range(7)}
132+
assert dict(hm) == witness
133+
134+
# update
135+
for i in range(5):
136+
hm[i] = 2 * i
137+
witness = {i: 2 * i for i in range(7)}
138+
assert dict(hm) == witness
139+
140+
# remove
141+
for i in range(0, 7, 2):
142+
del hm[i]
143+
witness = {i: 2 * i for i in range(0, 7, 2)}
144+
assert dict(hm) == witness
145+
146+
# contains
147+
assert 1 in hm
148+
assert 666 not in hm

0 commit comments

Comments
 (0)