diff --git a/data_structures/hashing/__init__.py b/data_structures/hashing/__init__.py new file mode 100644 index 000000000..b96ddd478 --- /dev/null +++ b/data_structures/hashing/__init__.py @@ -0,0 +1,6 @@ +from .hash_table import HashTable + +class QuadraticProbing(HashTable): + + def __init__(self): + super(self.__class__, self).__init__() diff --git a/data_structures/hashing/double_hash.py b/data_structures/hashing/double_hash.py new file mode 100644 index 000000000..60098cda0 --- /dev/null +++ b/data_structures/hashing/double_hash.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 + +from .hash_table import HashTable +from number_theory.prime_numbers import next_prime, check_prime + + +class DoubleHash(HashTable): + """ + Hash Table example with open addressing and Double Hash + """ + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def __hash_function_2(self, value, data): + + next_prime_gt = next_prime(value % self.size_table) \ + if not check_prime(value % self.size_table) else value % self.size_table #gt = bigger than + return next_prime_gt - (data % next_prime_gt) + + def __hash_double_function(self, key, data, increment): + return (increment * self.__hash_function_2(key, data)) % self.size_table + + def _colision_resolution(self, key, data=None): + i = 1 + new_key = self.hash_function(data) + + while self.values[new_key] is not None and self.values[new_key] != key: + new_key = self.__hash_double_function(key, data, i) if \ + self.balanced_factor() >= self.lim_charge else None + if new_key is None: break + else: i += 1 + + return new_key diff --git a/data_structures/hashing/hash_table.py b/data_structures/hashing/hash_table.py new file mode 100644 index 000000000..f0de128d1 --- /dev/null +++ b/data_structures/hashing/hash_table.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 +from number_theory.prime_numbers import next_prime + + +class HashTable: + """ + Basic Hash Table example with open addressing and linear probing + """ + + 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) + + diff --git a/data_structures/hashing/hash_table_with_linked_list.py b/data_structures/hashing/hash_table_with_linked_list.py new file mode 100644 index 000000000..9689e4fc9 --- /dev/null +++ b/data_structures/hashing/hash_table_with_linked_list.py @@ -0,0 +1,24 @@ +from .hash_table import HashTable +from collections import deque + + +class HashTableWithLinkedList(HashTable): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def _set_value(self, key, data): + self.values[key] = deque([]) if self.values[key] is None else self.values[key] + self.values[key].appendleft(data) + self._keys[key] = self.values[key] + + def balanced_factor(self): + return sum([self.charge_factor - len(slot) for slot in self.values])\ + / self.size_table * self.charge_factor + + def _colision_resolution(self, key, data=None): + if not (len(self.values[key]) == self.charge_factor + and self.values.count(None) == 0): + return key + return super()._colision_resolution(key, data) + + diff --git a/data_structures/hashing/number_theory/__init__.py b/data_structures/hashing/number_theory/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/data_structures/hashing/number_theory/prime_numbers.py b/data_structures/hashing/number_theory/prime_numbers.py new file mode 100644 index 000000000..8a521bc45 --- /dev/null +++ b/data_structures/hashing/number_theory/prime_numbers.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +""" + module to operations with prime numbers +""" + + +def check_prime(number): + """ + it's not the best solution + """ + special_non_primes = [0,1,2] + if number in special_non_primes[:2]: + return 2 + elif number == special_non_primes[-1]: + return 3 + + return all([number % i for i in range(2, number)]) + + +def next_prime(value, factor=1, **kwargs): + value = factor * value + first_value_val = value + + while not check_prime(value): + value += 1 if not ("desc" in kwargs.keys() and kwargs["desc"] is True) else -1 + + if value == first_value_val: + return next_prime(value + 1, **kwargs) + return value diff --git a/data_structures/hashing/quadratic_probing.py b/data_structures/hashing/quadratic_probing.py new file mode 100644 index 000000000..f7a9ac1ae --- /dev/null +++ b/data_structures/hashing/quadratic_probing.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 + +from .hash_table import HashTable + + +class QuadraticProbing(HashTable): + """ + Basic Hash Table example with open addressing using Quadratic Probing + """ + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def _colision_resolution(self, key, data=None): + i = 1 + new_key = self.hash_function(key + i*i) + + while self.values[new_key] is not None \ + and self.values[new_key] != key: + i += 1 + new_key = self.hash_function(key + i*i) if not \ + self.balanced_factor() >= self.lim_charge else None + + if new_key is None: + break + + return new_key