diff --git a/names/binary_search_tree.py b/names/binary_search_tree.py new file mode 100644 index 000000000..bd908691e --- /dev/null +++ b/names/binary_search_tree.py @@ -0,0 +1,65 @@ +class BSTNode: + def __init__(self, value): + self.value = value + self.left = None + self.right = None + + def insert(self, value): + # Insertion of a key, a new key is always inserted at leaf. + # We start searching a key from root + # till we hit a leaf node. Once a leaf node is found, + # the new node is added as a child of the leaf node. + if value < self.value: + #Go Left + if not self.left: + #add as leaf + self.left = BSTNode(value) + else: + #check again + self.left.insert(value) + else: + #Go Right + if not self.right: + self.right = BSTNode(value) + else: + self.right.insert(value) + + def contains(self, target): + # Searching a key + # To search a given key in Binary Search Tree, we first compare it with root, + # if the key is present at root, we return root. If key is greater than root's + # key, we recur for right subtree of root node. Otherwise we recur for left + # subtree. + if self.value == target: + return True + if target < self.value: + if not self.left: + return False + else: + return self.left.contains(target) + else: + if not self.right: + return False + else: + return self.right.contains(target) + + def get_max(self): + # Keep going right until you find a node without a child to the right + if not self: + return None + else: + if not self.right: + return self.value + else: + return self.right.get_max() + + def for_each(self, callback): + # We need to traverse the tree similar to how the print works in the demo + # For each value append it to the array + + # Call the function + callback(self.value) + if self.left: + self.left.for_each(callback) + if self.right: + self.right.for_each(callback) \ No newline at end of file diff --git a/names/names.py b/names/names.py index ea158997f..98f25cdb4 100644 --- a/names/names.py +++ b/names/names.py @@ -1,4 +1,5 @@ import time +from binary_search_tree import BSTNode start_time = time.time() @@ -10,13 +11,20 @@ names_2 = f.read().split("\n") # List containing 10000 names f.close() -duplicates = [] # Return the list of duplicates in this data structure +duplicates = [] -# Replace the nested for loops below with your improvements -for name_1 in names_1: - for name_2 in names_2: - if name_1 == name_2: - duplicates.append(name_1) +bst = BSTNode(names_1[0]) + +names2_dict = {} + +for name in names_2: + names2_dict[name] = 1 + +for name in names_1: + if names2_dict.get(name) == None: + pass + else: + duplicates.append(name) end_time = time.time() print (f"{len(duplicates)} duplicates:\n\n{', '.join(duplicates)}\n\n") diff --git a/names/test_binary_search_tree.py b/names/test_binary_search_tree.py new file mode 100644 index 000000000..95c4102d9 --- /dev/null +++ b/names/test_binary_search_tree.py @@ -0,0 +1,110 @@ +import unittest +import random +import sys +import io +from binary_search_tree import BSTNode + +class BSTNOdeTests(unittest.TestCase): + def setUp(self): + self.bst = BSTNode(5) + + def test_insert(self): + self.bst.insert(2) + self.bst.insert(3) + self.bst.insert(7) + self.bst.insert(6) + self.assertEqual(self.bst.left.right.value, 3) + self.assertEqual(self.bst.right.left.value, 6) + + def test_handle_dupe_insert(self): + self.bst2 = BSTNode(1) + self.bst2.insert(1) + self.assertEqual(self.bst2.right.value, 1) + + def test_contains(self): + self.bst.insert(2) + self.bst.insert(3) + self.bst.insert(7) + self.assertTrue(self.bst.contains(7)) + self.assertFalse(self.bst.contains(8)) + + def test_get_max(self): + self.assertEqual(self.bst.get_max(), 5) + self.bst.insert(30) + self.assertEqual(self.bst.get_max(), 30) + self.bst.insert(300) + self.bst.insert(3) + self.assertEqual(self.bst.get_max(), 300) + + def test_for_each(self): + arr = [] + cb = lambda x: arr.append(x) + + v1 = random.randint(1, 101) + v2 = random.randint(1, 101) + v3 = random.randint(1, 101) + v4 = random.randint(1, 101) + v5 = random.randint(1, 101) + + self.bst.insert(v1) + self.bst.insert(v2) + self.bst.insert(v3) + self.bst.insert(v4) + self.bst.insert(v5) + + self.bst.for_each(cb) + + self.assertTrue(5 in arr) + self.assertTrue(v1 in arr) + self.assertTrue(v2 in arr) + self.assertTrue(v3 in arr) + self.assertTrue(v4 in arr) + self.assertTrue(v5 in arr) + + def test_print_traversals(self): + # WARNING: Tests are for Print() + # Debug calls to Print() in functions will cause failure + + stdout_ = sys.stdout # Keep previous value + sys.stdout = io.StringIO() + + self.bst = BSTNode(1) + self.bst.insert(8) + self.bst.insert(5) + self.bst.insert(7) + self.bst.insert(6) + self.bst.insert(3) + self.bst.insert(4) + self.bst.insert(2) + + output = sys.stdout.getvalue() + self.assertEqual(output, "1\n2\n3\n4\n5\n6\n7\n8\n") + + self.bst.in_order_print(self.bst) + + sys.stdout = io.StringIO() + self.bst.bft_print(self.bst) + output = sys.stdout.getvalue() + self.assertTrue(output == "1\n8\n5\n3\n7\n2\n4\n6\n" or + output == "1\n8\n5\n7\n3\n6\n4\n2\n") + + sys.stdout = io.StringIO() + self.bst.dft_print(self.bst) + output = sys.stdout.getvalue() + self.assertTrue(output == "1\n8\n5\n7\n6\n3\n4\n2\n" or + output == "1\n8\n5\n3\n2\n4\n7\n6\n") + + sys.stdout = io.StringIO() + self.bst.pre_order_dft(self.bst) + output = sys.stdout.getvalue() + self.assertEqual(output, "1\n8\n5\n3\n2\n4\n7\n6\n") + + sys.stdout = io.StringIO() + self.bst.post_order_dft(self.bst) + output = sys.stdout.getvalue() + self.assertEqual(output, "2\n4\n3\n6\n7\n5\n8\n1\n") + + sys.stdout = stdout_ # Restore stdout + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/reverse/reverse.py b/reverse/reverse.py index 6116252d1..f5a3bec4d 100644 --- a/reverse/reverse.py +++ b/reverse/reverse.py @@ -39,4 +39,21 @@ def contains(self, value): return False def reverse_list(self, node, prev): - pass + # use recursion to solve this problem + # check if the list is empty + if node is None: + return "It's an empty list" + # store the node's next points to a new variable + current_next = node.get_next() + # reverse, set the node's next points to his prev + node.set_next(prev) + + # if current node is not the tail, continue the recursion, + # and reverse the points: node = current_next, prev = node... + if current_next is not None: + self.reverse_list(current_next,node) + # if the current node is the tail, set it head... + else: + self.head = node + + diff --git a/ring_buffer/ring_buffer.py b/ring_buffer/ring_buffer.py index 37e9fb0dd..a2683f4af 100644 --- a/ring_buffer/ring_buffer.py +++ b/ring_buffer/ring_buffer.py @@ -1,9 +1,19 @@ class RingBuffer: def __init__(self, capacity): - pass + self.capacity = capacity # capacity : max number in the buffer + self.data = [] # empty storage for appending data later + self.current_pos = 0 # current position index def append(self, item): - pass + if len(self.data) < self.capacity: + self.data.append(item) + + else: + self.data[self.current_pos] = item # the oldest one's position starting from 0 + + self.current_pos += 1 # then position plus 1 + self.current_pos = self.current_pos % (self.capacity) def get(self): - pass \ No newline at end of file + # return list of elements in correct order + return self.data \ No newline at end of file