diff --git a/names/binary_search_tree.py b/names/binary_search_tree.py new file mode 100644 index 000000000..e84987b6a --- /dev/null +++ b/names/binary_search_tree.py @@ -0,0 +1,170 @@ +""" +Binary search trees are a data structure that enforce an ordering over +the data they store. That ordering in turn makes it a lot more efficient +at searching for a particular piece of data in the tree. + +This part of the project comprises two days: +1. Implement the methods `insert`, `contains`, `get_max`, and `for_each` + on the BSTNode class. +2. Implement the `in_order_print`, `bft_print`, and `dft_print` methods + on the BSTNode class. +""" +class Stack: + def __init__(self): + self.storage = [] + + def __len__(self): + return len(self.storage) + + def push(self, value): + self.storage.append(value) + + def pop(self): + if len(self.storage) == 0: + return None + return self.storage.pop() + + def peek(self): + return self.storage[-1] + +class Queue: + def __init__(self): + self.storage = [] + + def __len__(self): + return len(self.storage) + + def enqueue(self, value): + self.storage.append(value) + + def dequeue(self): + if len(self.storage) == 0: + return None + return self.storage.pop(0) + + +class BSTNode: + def __init__(self, value): + self.value = value + self.left = None + self.right = None + + # Insert the given value into the tree + def insert(self, value): + if value < self.value: + if not self.left: + self.left = BSTNode(value) + else: + self.left.insert(value) + elif value >= self.value: + if not self.right: + self.right = BSTNode(value) + else: + self.right.insert(value) + + # Return True if the tree contains the value + # False if it does not + def contains(self, target): + if target == self.value: + return True + elif target < self.value: + if not self.left: + return False + else: + return self.left.contains(target) + elif target > self.value: + if not self.right: + return False + else: + return self.right.contains(target) + + # Return the maximum value found in the tree + def get_max(self): + if not self.value: + return None + if not self.right: + return self.value + else: + return self.right.get_max() + + # Call the function `fn` on the value of each node + def for_each(self, fn): + fn(self.value) + if self.left: + self.left.for_each(fn) + if self.right: + self.right.for_each(fn) + + # Part 2 ----------------------- + + # Print all the values in order from low to high + # Hint: Use a recursive, depth first traversal + def in_order_print(self): + if self.left: + self.left.in_order_print() + + print(self.value) + + if self.right: + self.right.in_order_print() + + # Print the value of every node, starting with the given node, + # in an iterative breadth first traversal + def bft_print(self): + queue = Queue() + queue.enqueue(self) + while queue.__len__() > 0: + node = queue.dequeue() + print(node.value) + if (node.left): + queue.enqueue(node.left) + if (node.right): + queue.enqueue(node.right) + + # Print the value of every node, starting with the given node, + # in an iterative depth first traversal + def dft_print(self): + stack = Stack() + stack.push(self) + while stack.__len__() > 0: + node = stack.pop() + print(node.value) + if(node.left): + stack.push(node.left) + if(node.right): + stack.push(node.right) + + # Stretch Goals ------------------------- + # Note: Research may be required + + # Print Pre-order recursive DFT + def pre_order_dft(self): + pass + + # Print Post-order recursive DFT + def post_order_dft(self): + pass + +""" +This code is necessary for testing the `print` methods +""" +bst = BSTNode(1) + +bst.insert(8) +bst.insert(5) +bst.insert(7) +bst.insert(6) +bst.insert(3) +bst.insert(4) +bst.insert(2) + +bst.bft_print() +bst.dft_print() + +# print("elegant methods") +# print("pre order") +# bst.pre_order_dft() +print("in order") +bst.in_order_print() +# print("post order") +# bst.post_order_dft() diff --git a/names/names.py b/names/names.py index ea158997f..080bae1c6 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() @@ -13,10 +14,22 @@ duplicates = [] # Return the list of duplicates in this data structure # Replace the nested for loops below with your improvements + +bst = BSTNode('M') + for name_1 in names_1: - for name_2 in names_2: - if name_1 == name_2: - duplicates.append(name_1) + bst.insert(name_1) + +for name_2 in names_2: + if bst.contains(name_2): + duplicates.append(name_2) + +# for name_1 in names_1: +# for name_2 in names_2: +# if name_1 == name_2: +# duplicates.append(name_1) + +# Runtime complexity is O(n^2) prior to optimization end_time = time.time() print (f"{len(duplicates)} duplicates:\n\n{', '.join(duplicates)}\n\n") @@ -26,3 +39,20 @@ # Python has built-in tools that allow for a very efficient approach to this problem # What's the best time you can accomplish? Thare are no restrictions on techniques or data # structures, but you may not import any additional libraries that you did not write yourself. + + +start_time = time.time() + +f = open('names_1.txt', 'r') +names_1 = f.read().split("\n") # List containing 10000 names +f.close() + +f = open('names_2.txt', 'r') +names_2 = f.read().split("\n") # List containing 10000 names +f.close() + +duplicates = set(names_1).intersection(names_2) + +end_time = time.time() +print (f"{len(duplicates)} duplicates:\n\n{', '.join(duplicates)}\n\n") +print (f"runtime: {end_time - start_time} seconds") \ No newline at end of file diff --git a/reverse/reverse.py b/reverse/reverse.py index 6116252d1..a93024701 100644 --- a/reverse/reverse.py +++ b/reverse/reverse.py @@ -39,4 +39,8 @@ def contains(self, value): return False def reverse_list(self, node, prev): - pass + if node is None: + self.head = prev + return + self.reverse_list(node.get_next(), node) + node.set_next(prev) diff --git a/ring_buffer/ring_buffer.py b/ring_buffer/ring_buffer.py index 37e9fb0dd..3790bd841 100644 --- a/ring_buffer/ring_buffer.py +++ b/ring_buffer/ring_buffer.py @@ -1,9 +1,40 @@ class RingBuffer: def __init__(self, capacity): - pass + self.capacity = capacity + self.storage = [] + self.oldest_index = 0 + def append(self, item): - pass + if len(self.storage) < self.capacity: + self.storage.append(item) + else: + self.storage[self.oldest_index] = item + if self.oldest_index < len(self.storage) - 1: + self.oldest_index += 1 + else: + self.oldest_index = 0 def get(self): - pass \ No newline at end of file + return self.storage + + +# buffer = RingBuffer(3) + +# buffer.get() # should return [] + +# buffer.append('a') +# buffer.append('b') +# buffer.append('c') + +# buffer.get() # should return ['a', 'b', 'c'] + +# # 'd' overwrites the oldest value in the ring buffer, which is 'a' +# buffer.append('d') + +# buffer.get() # should return ['d', 'b', 'c'] + +# buffer.append('e') +# buffer.append('f') + +# buffer.get() # should return ['d', 'e', 'f'] \ No newline at end of file