Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 118 additions & 0 deletions Binary Tree/NonRecursiveSegmentTree.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
from __future__ import annotations

from typing import Callable, TypeVar

T = TypeVar("T")


class SegmentTree:
def __init__(self, arr: list[T], fnc: Callable[[T, T], T]) -> None:
"""
Segment Tree constructor, it works just with commutative combiner.
:param arr: list of elements for the segment tree
:param fnc: commutative function for combine two elements
>>> SegmentTree(['a', 'b', 'c'], lambda a, b: '{}{}'.format(a, b)).query(0, 2)
'abc'
>>> SegmentTree([(1, 2), (2, 3), (3, 4)],
... lambda a, b: (a[0] + b[0], a[1] + b[1])).query(0, 2)
(6, 9)
"""
self.N = len(arr)
self.st = [None for _ in range(len(arr))] + arr
self.fn = fnc
self.build()

def build(self) -> None:
for p in range(self.N - 1, 0, -1):
self.st[p] = self.fn(self.st[p * 2], self.st[p * 2 + 1])

def update(self, p: int, v: T) -> None:
"""
Update an element in log(N) time
:param p: position to be update
:param v: new value
>>> st = SegmentTree([3, 1, 2, 4], min)
>>> st.query(0, 3)
1
>>> st.update(2, -1)
>>> st.query(0, 3)
-1
"""
p += self.N
self.st[p] = v
while p > 1:
p = p // 2
self.st[p] = self.fn(self.st[p * 2], self.st[p * 2 + 1])

def query(self, l: int, r: int) -> T: # noqa: E741
"""
Get range query value in log(N) time
:param l: left element index
:param r: right element index
:return: element combined in the range [l, r]
>>> st = SegmentTree([1, 2, 3, 4], lambda a, b: a + b)
>>> st.query(0, 2)
6
>>> st.query(1, 2)
5
>>> st.query(0, 3)
10
>>> st.query(2, 3)
7
"""
l, r = l + self.N, r + self.N # noqa: E741
res = None
while l <= r: # noqa: E741
if l % 2 == 1:
res = self.st[l] if res is None else self.fn(res, self.st[l])
if r % 2 == 0:
res = self.st[r] if res is None else self.fn(res, self.st[r])
l, r = (l + 1) // 2, (r - 1) // 2
return res


if __name__ == "__main__":
from functools import reduce

test_array = [1, 10, -2, 9, -3, 8, 4, -7, 5, 6, 11, -12]

test_updates = {
0: 7,
1: 2,
2: 6,
3: -14,
4: 5,
5: 4,
6: 7,
7: -10,
8: 9,
9: 10,
10: 12,
11: 1,
}

min_segment_tree = SegmentTree(test_array, min)
max_segment_tree = SegmentTree(test_array, max)
sum_segment_tree = SegmentTree(test_array, lambda a, b: a + b)

def test_all_segments():
"""
Test all possible segments
"""
for i in range(len(test_array)):
for j in range(i, len(test_array)):
min_range = reduce(min, test_array[i : j + 1])
max_range = reduce(max, test_array[i : j + 1])
sum_range = reduce(lambda a, b: a + b, test_array[i : j + 1])
assert min_range == min_segment_tree.query(i, j)
assert max_range == max_segment_tree.query(i, j)
assert sum_range == sum_segment_tree.query(i, j)

test_all_segments()

for index, value in test_updates.items():
test_array[index] = value
min_segment_tree.update(index, value)
max_segment_tree.update(index, value)
sum_segment_tree.update(index, value)
test_all_segments()
77 changes: 77 additions & 0 deletions hashtable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
from number_theory.prime_numbers import next_prime

class HashTable:

def __init__(self, size_table, charge_factor=None, lim_charge=None):
self.size_table = size_table
self.values = [None] * self.size_table
self.lim_charge = 0.75 if lim_charge is None else lim_charge
self.charge_factor = 1 if charge_factor is None else charge_factor
self.__aux_list = []
self._keys = {}

def keys(self):
return self._keys

def balanced_factor(self):
return sum([1 for slot in self.values
if slot is not None]) / (self.size_table * self.charge_factor)

def hash_function(self, key):
return key % self.size_table

def _step_by_step(self, step_ord):

print("step {0}".format(step_ord))
print([i for i in range(len(self.values))])
print(self.values)

def bulk_insert(self, values):
i = 1
self.__aux_list = values
for value in values:
self.insert_data(value)
self._step_by_step(i)
i += 1

def _set_value(self, key, data):
self.values[key] = data
self._keys[key] = data

def _colision_resolution(self, key, data=None):
new_key = self.hash_function(key + 1)

while self.values[new_key] is not None \
and self.values[new_key] != key:

if self.values.count(None) > 0:
new_key = self.hash_function(new_key + 1)
else:
new_key = None
break

return new_key

def rehashing(self):
survivor_values = [value for value in self.values if value is not None]
self.size_table = next_prime(self.size_table, factor=2)
self._keys.clear()
self.values = [None] * self.size_table #hell's pointers D: don't DRY ;/
map(self.insert_data, survivor_values)

def insert_data(self, data):
key = self.hash_function(data)

if self.values[key] is None:
self._set_value(key, data)

elif self.values[key] == data:
pass

else:
colision_resolution = self._colision_resolution(key, data)
if colision_resolution is not None:
self._set_value(colision_resolution, data)
else:
self.rehashing()
self.insert_data(data)