class ConsistentHasher: def __init__(self): self.nodes = BST() self.id_to_node = dict() def hash(self, item, limit=4294967295): id_hash = hashlib.sha512(item.encode()) id_hash_int = int.from_bytes(id_hash.digest(), 'big') final_id = id_hash_int % limit return final_id def add_node(self, node_name): hash_id = self.hash(node_name) self.nodes.insert(hash_id) self.id_to_node[hash_id] = node_name def remove_node(self, node_name): hash_id = self.hash(node_name) removed = self.nodes.remove(hash_id) print('Removed %s: %r' % (node_name, removed)) return self.id_to_node.pop(hash_id, None) def assign_key_to_node(self, key): key_hash_id = self.hash(key) assigned_node_id = self.nodes.find_next_bigger_elem(key_hash_id) if assigned_node_id is None: print('Failed to assign key %s (hash = %d) to any node!' % (key, key_hash_id)) return # print('Key %s was hashed to value %d, and was assigned to node %s with id %d' % (key, key_hash_id, self.id_to_node[assigned_node_id], assigned_node_id)) return self.id_to_node[assigned_node_id]
def test_contains(): bst = BST() for i in range(1, 11): bst.insert(i) assert bst.contains(1) assert bst.contains(5) assert not bst.contains(15)
def test_depth(): bst = BST() bst.insert(5) assert bst.depth(node=bst.root) == 1 bst.insert(3) bst.insert(4) bst.insert(6) assert bst.depth(node=bst.root) == 3
def test_depth_collatz(): bst = BST() for i in range(1, 11): if not i % 2: i /= 2 else: i = i * 3 + 1 bst.insert(i) assert bst.depth(bst.root) == 5
def test_depth_collatz(): bst = BST() for i in range(1, 11): if not i % 2: i /= 2 else: i = i * 3 + 1 bst.insert(i) assert bst.depth(bst.root) == 5
def test_size(): bst = BST() assert bst.size() == 0 bst.insert(5) assert bst.size() == 1 bst.insert(5) assert bst.size() == 1
def test_depth(): bst = BST() bst.insert(5) assert bst.depth(node=bst.root) == 1 bst.insert(3) bst.insert(4) bst.insert(6) assert bst.depth(node=bst.root) == 3
def test_size(): bst = BST() assert bst.size() == 0 bst.insert(5) assert bst.size() == 1 bst.insert(5) assert bst.size() == 1
def test_insert(): bst = BST() bst.insert(3) assert bst.root.value == 3 bst.insert(5) assert bst.root.r_child.value == 5 assert bst.root.r_child.parent is bst.root bst.insert(2) assert bst.root.l_child.value == 2 assert bst.root.l_child.parent is bst.root
def test_left_balance(): bst = BST() bst.insert(5) bst.insert(4) bst.insert(3) bst.insert(6) assert bst.balance() == 1
def test_right_balance(): bst = BST() bst.insert(5) bst.insert(6) bst.insert(7) bst.insert(3) assert bst.balance() == -1
def test_bst(self): numbers = [10, 15, 3, 6, 12, 20, 1, 0] bst = BST() for num in numbers: bst.insert(num) ordered_nums = bst.traverse_inorder() print(ordered_nums) for num in numbers: successor = bst.find_next_bigger_elem(num) if successor is not None: print('Successor of %d is %d' % (num, successor)) else: print('Successor of %d is %s' % (num, 'None')) predecessor = bst.find_previous_smaller_elem(num) if predecessor is not None: print('Predecessor of %d is %d' % (num, predecessor)) else: print('Predecessor of %d is %s' % (num, 'None')) print('\n') num = -1 # Does not exist in the list successor = bst.find_next_bigger_elem(num) if successor is not None: print('Successor of %d is %d' % (num, successor)) else: print('Successor of %d is %s' % (num, 'None')) print('\n') num = 1 removed = bst.remove(num) if removed is not None: print('%d removed from tree: %s' % (num, " ".join(str(x) for x in bst.traverse_inorder()))) else: print('%d was not found in the tree' % num)
def test_insert(): bst = BST() bst.insert(3) assert bst.root.value == 3 bst.insert(5) assert bst.root.r_child.value == 5 assert bst.root.r_child.parent is bst.root bst.insert(2) assert bst.root.l_child.value == 2 assert bst.root.l_child.parent is bst.root
def test_contains(): bst = BST() for i in range(1, 11): bst.insert(i) assert bst.contains(1) assert bst.contains(5) assert not bst.contains(15)
def test_left_balance(): bst = BST() bst.insert(5) bst.insert(4) bst.insert(3) bst.insert(6) assert bst.balance() == 1
def test_right_balance(): bst = BST() bst.insert(5) bst.insert(6) bst.insert(7) bst.insert(3) assert bst.balance() == -1
class ConsistentHasher: def __init__(self): self.nodes = BST() self.id_to_node = dict() # Note: we need a deterministic hash function. Python hashlib's hash() is not deterministic, and will return # a different hash value on different runs. def hash(self, item, limit=4294967295): id_hash = hashlib.sha512(item.encode()) id_hash_int = int.from_bytes( id_hash.digest(), 'big' ) # Uses explicit byteorder for system-agnostic reproducibility final_id = id_hash_int % limit return final_id def hash2(self, item): return zlib.adler32(str.encode(item)) & 0xffffffff def add_node(self, node_name): hash_id = self.hash(node_name) self.nodes.insert(hash_id) self.id_to_node[hash_id] = node_name def remove_node(self, node_name): hash_id = self.hash(node_name) removed = self.nodes.remove(hash_id) print('Removed %s: %r' % (node_name, removed)) return self.id_to_node.pop(hash_id, None) def assign_key_to_node(self, key): key_hash_id = self.hash(key) assigned_node_id = self.nodes.find_next_bigger_elem(key_hash_id) if assigned_node_id is None: print('Failed to assign key %s (hash = %d) to any node!' % (key, key_hash_id)) return # print('Key %s was hashed to value %d, and was assigned to node %s with id %d' % (key, key_hash_id, self.id_to_node[assigned_node_id], assigned_node_id)) return self.id_to_node[assigned_node_id]
def __init__(self): self.nodes = BST() self.id_to_node = dict()
def make_bst(): bst = BST() return bst
def test_depth_all_left(): bst = BST() for i in range(110,10,-10): bst.insert(i) assert bst.depth(bst.root) == 10
def test_depth_all_left(): bst = BST() for i in range(110, 10, -10): bst.insert(i) assert bst.depth(bst.root) == 10
def test_bst(): assert BST() is not None