diff --git a/02_hash_maps/hm.py b/02_hash_maps/hm.py index faeff91..c91d489 100644 --- a/02_hash_maps/hm.py +++ b/02_hash_maps/hm.py @@ -129,6 +129,57 @@ class HMTableCollision(HashMap): return h % self._hash_size +class HashMapWithItem(): + """ + This implementation USES _HashMapItems + Also, this implementation will return an error in case of a collision. + Data will not be lost, but another key will have to be used. + """ + def __init__(self, hash_size=513): + self._hash_size = hash_size + self._size = 0 + self.hmap = [None] * self._hash_size + + def add(self, key, value): + """ + Adds the provided value to the hashmap. + Raises an Exception if a collision is detected + """ + my_key = self._hash(key) + if self.hmap[my_key] == None: + self.hmap[my_key] = value + self._size += 1 + else: + raise Exception("Collision detected at index %d", key) + + def get(self, key): + """ + Finds the element in the hash table that may contain the id for + the string we are looking for + """ + my_key = self._hash(key) + return self.hmap[my_key] + + def size(self): + return self._size + + def _hash(self, value): + """ + Generates a hash for the given value. + The input is expected to be a String, with only ASCII characters. + + # hash function taken from HT3. + # We shift and add : << 4 is a *16 + """ + if len(value) < 1: + raise Exception("Size of value must be greater than one") + + h = 0 + for letter in value: + h = (h << 4) + ord(letter) + + return h % self._hash_size + class HMNeighbourCollision(): def __init__(self, hash_size=513): self._hash_size = hash_size diff --git a/02_hash_maps/hm_test.py b/02_hash_maps/hm_test.py index 985a78e..2924703 100644 --- a/02_hash_maps/hm_test.py +++ b/02_hash_maps/hm_test.py @@ -14,62 +14,62 @@ class test_hash_map_neighbour_collision(unittest.TestCase): def test__find_free_idx(self): hm = HMNeighbourCollision() - + key = "One" value = "Ibiza" - + my_key = hm._hash(key) idx = hm._find_free_idx(my_key) self.assertEqual(my_key, idx) - + hm.add(key, value) self.assertEqual(hm.size(), 1) - + # We move one up - idx = hm._find_free_idx(my_key) + idx = hm._find_free_idx(my_key) self.assertEqual(my_key - 1, idx) - + hm.add(key, "Ibiza2") - self.assertEqual(hm.size(), 2) + self.assertEqual(hm.size(), 2) # We move one down - idx = hm._find_free_idx(my_key) + idx = hm._find_free_idx(my_key) self.assertEqual(my_key + 1, idx) hm.add(key, "Ibiza3") - self.assertEqual(hm.size(), 3) + self.assertEqual(hm.size(), 3) # We move two up - idx = hm._find_free_idx(my_key) + idx = hm._find_free_idx(my_key) self.assertEqual(my_key - 2, idx) class test_hash_map_table_collision(unittest.TestCase): def test_add(self): hm = HMTableCollision() - + hm.add("a", "Ibiza") self.assertEqual(hm.size(), 1) - + hm.add("a", "Ibiza2") - self.assertEqual(hm.size(), 2) + self.assertEqual(hm.size(), 2) def test_get(self): - + hm = HMTableCollision() value = "" self.assertRaises(Exception, lambda x : hm.get(value)) - + key = "One" value = "Ibiza" hm.add(key, value) key2 = "Two" - value2 = "NY" + value2 = "NY" hm.add(key2, value2) hm.add("Three", "Berlin") hm.add("Four", "Chicago") - + value3 = "Ibiza2" hm.add(key, value3) @@ -81,15 +81,15 @@ class test_hash_map_table_collision(unittest.TestCase): self.assertEqual(hm.get(key), [value, value3]) -class test_hash_map(unittest.TestCase): +class test_hash_map_with_item(unittest.TestCase): def test_hash_size(self): hm = HashMap() self.assertEqual(hm._hash_size, 513) - + hm = HashMap(1025) self.assertEqual(hm._hash_size, 1025) - + def test_size(self): hm = HashMap() @@ -97,10 +97,10 @@ class test_hash_map(unittest.TestCase): def test__hash(self): hm = HashMap() - + value = "a" self.assertEqual(hm._hash(value), ord(value)) - + value = "test" self.assertEqual(hm._hash(value), 208) @@ -110,7 +110,7 @@ class test_hash_map(unittest.TestCase): def test_add(self): hm = HashMap() - + hm.add("a", "Ibiza") self.assertEqual(hm.size(), 1) @@ -119,23 +119,79 @@ class test_hash_map(unittest.TestCase): self.assertEqual(hm.size(), 1) def test_get(self): - + hm = HashMap() value = "" self.assertRaises(Exception, lambda x : hm.get(value)) - + key = "One" value = "Ibiza" hm.add(key, value) - + hm.add("Two", "NY") hm.add("Three", "Berlin") hm.add("Four", "Chicago") - + self.assertEqual(hm.size(), 4) self.assertEqual(hm.get(key), value) self.assertEqual(hm.get("Five"), None) - + +class test_hash_map(unittest.TestCase): + + def test_hash_size(self): + hm = HashMap() + self.assertEqual(hm._hash_size, 513) + + hm = HashMap(1025) + self.assertEqual(hm._hash_size, 1025) + + + def test_size(self): + hm = HashMap() + self.assertEqual(hm.size(), 0) + + def test__hash(self): + hm = HashMap() + + value = "a" + self.assertEqual(hm._hash(value), ord(value)) + + value = "test" + self.assertEqual(hm._hash(value), 208) + + value = "" + self.assertRaises(Exception, lambda x : hm._hash(value)) + + + def test_add(self): + hm = HashMap() + + hm.add("a", "Ibiza") + self.assertEqual(hm.size(), 1) + + # Tests Collision + self.assertRaises(Exception, lambda x : hm.add("a", "Ibiza")) + self.assertEqual(hm.size(), 1) + + def test_get(self): + + hm = HashMap() + value = "" + self.assertRaises(Exception, lambda x : hm.get(value)) + + key = "One" + value = "Ibiza" + hm.add(key, value) + + hm.add("Two", "NY") + hm.add("Three", "Berlin") + hm.add("Four", "Chicago") + + self.assertEqual(hm.size(), 4) + + self.assertEqual(hm.get(key), value) + self.assertEqual(hm.get("Five"), None) + if __name__ == "__main__": unittest.main()