diff --git a/names/binary_search_tree.py b/names/binary_search_tree.py new file mode 100644 index 000000000..4bec74151 --- /dev/null +++ b/names/binary_search_tree.py @@ -0,0 +1,35 @@ +class BinarySearchTree: + def __init__(self, value): + self.value = value + self.left = None + self.right = None + self.count = 1 + +''' Insert given value into tree . If no Node , insert new node . If Node , implement recursion . ''' + +''' If tree contains value , return TRUE . Return False otherwise . ''' + + def insert(self, value): + if value < self.value: + if not self.left: + self.left = BinarySearchTree(value) + else: + self.left.insert(value) + else: + if not self.right: + self.right = BinarySearchTree(value) + else: + self.right.insert(value) + +''' Implement recursion ''' + def contains(self, target): + if target == self.value: + return True + elif target < self.value: + if self.left is None: + return False + return self.left.contains(target) + else: + if self.right is None: + return False + return self.right.contains(target) \ No newline at end of file diff --git a/names/names.py b/names/names.py index ea158997f..c6f48ee17 100644 --- a/names/names.py +++ b/names/names.py @@ -1,22 +1,39 @@ import time +# Import Binary Search +from binary_search_tree import BinarySearchTree start_time = time.time() -f = open('names_1.txt', 'r') +f = open('names/names_1.txt', 'r') names_1 = f.read().split("\n") # List containing 10000 names f.close() -f = open('names_2.txt', 'r') +f = open('names/names_2.txt', 'r') names_2 = f.read().split("\n") # List containing 10000 names f.close() duplicates = [] # Return the list of duplicates in this data structure # 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) +''' +# Above takes roughly 7 secs - 0(n^2) + +# Starting in middle of alphabet +bst = BinarySearchTree('N') + +for name in names_1: + bst.insert(name) + +for name in names_2: + if bst.contains(name): + duplicates.append(name) + +#BST method runtime: 0.1453089714050293 seconds - 0(n * log(n)) end_time = time.time() print (f"{len(duplicates)} duplicates:\n\n{', '.join(duplicates)}\n\n") diff --git a/reverse/reverse.py b/reverse/reverse.py index 6116252d1..749ed41de 100644 --- a/reverse/reverse.py +++ b/reverse/reverse.py @@ -1,7 +1,9 @@ class Node: def __init__(self, value=None, next_node=None): - self.value = value - self.next_node = next_node + '''Holds Node value''' + self.value = value + '''references nxt Node''' + self.next_node = next_node def get_value(self): return self.value @@ -10,11 +12,13 @@ def get_next(self): return self.next_node def set_next(self, new_next): - self.next_node = new_next + '''sets nxt Node refrence to whatever Node is passed in''' + self.next_node = new_next class LinkedList: def __init__(self): - self.head = None + ''' Head ''' + self.head = None def add_to_head(self, value): node = Node(value) @@ -28,15 +32,31 @@ def contains(self, value): if not self.head: return False - current = self.head + '''Reference current Node , update as we iterate over list''' + current = self.head while current: if current.get_value() == value: - return True + '''Check if Node is valid , return True if Node value matches target value''' + return True - current = current.get_next() + '''update to point to next Node''' + current = current.get_next() return False def reverse_list(self, node, prev): - pass + if self.head is None: + return '...' + prev = None + cur = self.head + nxt = self.head.get_next() + + while cur != None: + cur.set_next(prev) + prev = cur + cur = nxt + if nxt != None: + nxt = cur.get_next() + + self.head = prev diff --git a/ring_buffer/doubly_linked_list.py b/ring_buffer/doubly_linked_list.py new file mode 100644 index 000000000..ebfc9cb7b --- /dev/null +++ b/ring_buffer/doubly_linked_list.py @@ -0,0 +1,138 @@ +"""Each ListNode holds a reference to its previous node +as well as its next node in the List.""" + + +class ListNode: + def __init__(self, value, prev=None, next=None): + self.value = value + self.prev = prev + self.next = next + + """Wrap the given value in a ListNode and insert it + after this node. Note that this node could already + have a next node it is point to.""" + def insert_after(self, value): + current_next = self.next + self.next = ListNode(value, self, current_next) + if current_next: + current_next.prev = self.next + + """Wrap the given value in a ListNode and insert it + before this node. Note that this node could already + have a previous node it is point to.""" + def insert_before(self, value): + current_prev = self.prev + self.prev = ListNode(value, current_prev, self) + if current_prev: + current_prev.next = self.prev + + """Rearranges this ListNode's previous and next pointers + accordingly, effectively deleting this ListNode.""" + def delete(self): + if self.prev: + self.prev.next = self.next + if self.next: + self.next.prev = self.prev + + +"""Our doubly-linked list class. It holds references to +the list's head and tail nodes.""" + + +class DoublyLinkedList: + def __init__(self, node=None): + self.head = node + self.tail = node + self.length = 1 if node is not None else 0 + + def __len__(self): + return self.length + + """Wraps the given value in a ListNode and inserts it + as the new head of the list. Don't forget to handle + the old head node's previous pointer accordingly.""" + def add_to_head(self, value): + new_node = ListNode(value, None, None) + self.length += 1 + if not self.head and not self.tail: + self.head = new_node + self.tail = new_node + else: + new_node.next = self.head + self.head.prev = new_node + self.head = new_node + + """Removes the List's current head node, making the + current head's next node the new head of the List. + Returns the value of the removed Node.""" + def remove_from_head(self): + value = self.head.value + self.delete(self.head) + return value + + """Wraps the given value in a ListNode and inserts it + as the new tail of the list. Don't forget to handle + the old tail node's next pointer accordingly.""" + def add_to_tail(self, value): + new_node = ListNode(value, None, None) + self.length += 1 + if not self.head and not self.tail: + self.head = new_node + self.tail = new_node + else: + new_node.prev = self.tail + self.tail.next = new_node + self.tail = new_node + + """Removes the List's current tail node, making the + current tail's previous node the new tail of the List. + Returns the value of the removed Node.""" + def remove_from_tail(self): + value = self.tail.value + self.delete(self.tail) + return value + + """Removes the input node from its current spot in the + List and inserts it as the new head node of the List.""" + def move_to_front(self, node): + if node is self.head: + return + value = node.value + self.delete(node) + self.add_to_head(value) + + """Removes the input node from its current spot in the + List and inserts it as the new tail node of the List.""" + def move_to_end(self, node): + if node is self.tail: + return + value = node.value + self.delete(node) + self.add_to_tail(value) + + """Removes a node from the list and handles cases where + the node was the head or the tail""" + def delete(self, node): + self.length -= 1 + if self.head is self.tail: + self.head = None + self.tail = None + elif self.head is node: + self.head = node.next + node.delete() + elif self.tail is node: + self.tail = node.prev + node.delete() + else: + node.delete() + + """Returns the highest value currently in the list""" + def get_max(self): + max_value = self.head.value + current = self.head + while current is not None: + if current.value > max_value: + max_value = current.value + current = current.next + + return max_value \ No newline at end of file diff --git a/ring_buffer/ring_buffer.py b/ring_buffer/ring_buffer.py index 37e9fb0dd..f6e3d0db5 100644 --- a/ring_buffer/ring_buffer.py +++ b/ring_buffer/ring_buffer.py @@ -1,4 +1,44 @@ +from doubly_linked_list import DoublyLinkedList + +# Look to see whether list has reached full capacity +# if so - replace the current item with the new item +# move current item to next item in list +# if current item = tail, next value is head +# if not at capacity then add to end of storage +# if the storage had no items then set current item to new item +# add node data to list and move pointer + class RingBuffer: + def __init__(self, capacity): + self.capacity = capacity + self.current = None + self.storage = DoublyLinkedList() + + def append(self, item): + if self.capacity == len(self.storage): + self.current.value = item + if self.current == self.storage.tail: + self.current = self.storage.head + else: + self.current = self.current.next + else: + self.storage.add_to_tail(item) + if len(self.storage) == 1: + self.current = self.storage.head + + def get(self): + list_buffer_contents = [] + + node = self.storage.head + while node is not None: + list_buffer_contents.append(node.value) + node = node.next + + return list_buffer_contents + +'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +class ArrayRingBuffer: def __init__(self, capacity): pass