From 5c4bdca606157e467d99e502282b1b0b5b9000b7 Mon Sep 17 00:00:00 2001 From: Christian Lorenzo Date: Tue, 22 Sep 2020 19:50:50 -0700 Subject: [PATCH 01/10] Update binary_search_tree.py Finished with Binary Tree class. --- binary_search_tree/binary_search_tree.py | 64 ++++++++++++++++++++---- 1 file changed, 55 insertions(+), 9 deletions(-) diff --git a/binary_search_tree/binary_search_tree.py b/binary_search_tree/binary_search_tree.py index d80d9f6282..12637b8d26 100644 --- a/binary_search_tree/binary_search_tree.py +++ b/binary_search_tree/binary_search_tree.py @@ -9,6 +9,10 @@ 2. Implement the `in_order_print`, `bft_print`, and `dft_print` methods on the BSTNode class. """ + +import sys +sys.path.extend(["queue", "stack", "binary_search_tree"]) + class BSTNode: def __init__(self, value): self.value = value @@ -17,44 +21,86 @@ def __init__(self, value): # Insert the given value into the tree def insert(self, value): - pass + if value < self.value: + if self.left is None: + 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): - pass + if target == self.value: + return True + elif target < self.value: + return self.left.contains(target) if self.left else False + else: + return self.right.contains(target) if self.right else False # Return the maximum value found in the tree def get_max(self): - pass + if self.right is None: + return self.value + return self.right.get_max() # Call the function `fn` on the value of each node def for_each(self, fn): - pass + 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): - pass + if not self: + return + 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): - pass + queue = Queue() + queue.put(node) + while not queue.empty(): + node = queue.get() + print(node.value) + if node.left: + queue.put(node.left) + if node.right: + queue.put(node.right) # Print the value of every node, starting with the given node, # in an iterative depth first traversal def dft_print(self): - pass + stack = Stack() + stack.push(node) + while not stack.is Empty(): + node = stack.pop() + print(node.value) + if node.right: + stack.push(node.right) + if node.left: + stack.push(node.left) # Stretch Goals ------------------------- # Note: Research may be required - + # Depth First Traversal -------------------------------- # Print Pre-order recursive DFT def pre_order_dft(self): - pass + # Print Post-order recursive DFT def post_order_dft(self): From 72ccb580ae65238e4263f79bda45e4e8c4f91cc7 Mon Sep 17 00:00:00 2001 From: Christian Lorenzo Date: Tue, 22 Sep 2020 20:00:13 -0700 Subject: [PATCH 02/10] Created a display File Created BSTD Displayer --- binary_search_tree/binary_search_tree.py | 8 ++- .../binary_search_tree_displayer.py | 57 +++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 binary_search_tree/binary_search_tree_displayer.py diff --git a/binary_search_tree/binary_search_tree.py b/binary_search_tree/binary_search_tree.py index 12637b8d26..d33bb091f7 100644 --- a/binary_search_tree/binary_search_tree.py +++ b/binary_search_tree/binary_search_tree.py @@ -100,7 +100,13 @@ def dft_print(self): # Depth First Traversal -------------------------------- # Print Pre-order recursive DFT def pre_order_dft(self): - + if not self: + return + print(self.value) + if self.left: + self.left.pre_order_dft() + if self.right: + self.right.pre_order_dft() # Print Post-order recursive DFT def post_order_dft(self): diff --git a/binary_search_tree/binary_search_tree_displayer.py b/binary_search_tree/binary_search_tree_displayer.py new file mode 100644 index 0000000000..55e5e1dc4e --- /dev/null +++ b/binary_search_tree/binary_search_tree_displayer.py @@ -0,0 +1,57 @@ + + +# display source code: https://stackoverflow.com/questions/34012886/print-binary-tree-level-by-level-in-python + +class BSTDisplayer: + def __init__(self, bst): + self.bst = bst + + def display(self): + lines, *_ = self._display_aux(self.bst) + for line in lines: + print(line) + + def _display_aux(self, bst_node): + """Returns list of strings, width, height, and horizontal coordinate of the root.""" + # No child. + if bst_node.right is None and bst_node.left is None: + line = '%s' % bst_node.value + width = len(line) + height = 1 + middle = width // 2 + return [line], width, height, middle + + # Only left child. + if bst_node.right is None: + lines, n, p, x = self._display_aux(bst_node.left) + s = '%s' % bst_node.value + u = len(s) + first_line = (x + 1) * ' ' + (n - x - 1) * '_' + s + second_line = x * ' ' + '/' + (n - x - 1 + u) * ' ' + shifted_lines = [line + u * ' ' for line in lines] + return [first_line, second_line] + shifted_lines, n + u, p + 2, n + u // 2 + + # Only right child. + if bst_node.left is None: + lines, n, p, x = self._display_aux(bst_node.right) + s = '%s' % bst_node.value + u = len(s) + first_line = s + x * '_' + (n - x) * ' ' + second_line = (u + x) * ' ' + '\\' + (n - x - 1) * ' ' + shifted_lines = [u * ' ' + line for line in lines] + return [first_line, second_line] + shifted_lines, n + u, p + 2, u // 2 + + # Two children. + left, n, p, x = self._display_aux(bst_node.left) + right, m, q, y = self._display_aux(bst_node.right) + s = '%s' % bst_node.value + u = len(s) + first_line = (x + 1) * ' ' + (n - x - 1) * '_' + s + y * '_' + (m - y) * ' ' + second_line = x * ' ' + '/' + (n - x - 1 + u + y) * ' ' + '\\' + (m - y - 1) * ' ' + if p < q: + left += [n * ' '] * (q - p) + elif q < p: + right += [m * ' '] * (p - q) + zipped_lines = zip(left, right) + lines = [first_line, second_line] + [a + u * ' ' + b for a, b in zipped_lines] + return lines, n + m + u, max(p, q) + 2, n + u // 2 \ No newline at end of file From 2182a77e5c84b55376b4dabf7161c530386e2b98 Mon Sep 17 00:00:00 2001 From: Christian Lorenzo Date: Wed, 16 Sep 2020 20:10:53 -0700 Subject: [PATCH 03/10] Update queue.py Class Queue finished. --- queue/queue.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/queue/queue.py b/queue/queue.py index 0d2599ded7..d345aa37f5 100644 --- a/queue/queue.py +++ b/queue/queue.py @@ -16,13 +16,18 @@ class Queue: def __init__(self): self.size = 0 - # self.storage = ? + self.storage = LinkedList() def __len__(self): - pass + self.size def enqueue(self, value): - pass + self.storage.add_to_tail(value) + self.size += 1 def dequeue(self): - pass + if self.isEmpty() == 0: + return None + else: + self.size -= 1 + return self.storage.remove_head() From 0b6db03e2261502b0d0f99c26d37df3d76680844 Mon Sep 17 00:00:00 2001 From: Christian Lorenzo Date: Wed, 16 Sep 2020 21:08:24 -0700 Subject: [PATCH 04/10] Finished Singly List --- singly_linked_list/singly_linked_list.py | 103 +++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/singly_linked_list/singly_linked_list.py b/singly_linked_list/singly_linked_list.py index e69de29bb2..09cd067c5f 100644 --- a/singly_linked_list/singly_linked_list.py +++ b/singly_linked_list/singly_linked_list.py @@ -0,0 +1,103 @@ + +# Node +class Node: + def __init__(self, value=None, next=None): + self.value = value + self.next = next + + def __repr__(self): + return self.value + + def get_value(self): + return self.value + + def get_next(self): + return self.next + + def set_next(self, new_next): + self.next = new_next + +# Singly list + +class LinkedList: + def __init__(self): + self.head = None + self.tail = None + + def __repr__(self): + node = self.head + nodes = [] + while node is not None: + nodes.append(node.data) + node = node.next + nodes.append("None") + return " -> ".join(nodes) + +# add_to_head performance: + def add_to_head(self, value): + new_node = Node(value, self.head) + self.head = new_node + if not self.tail: + # set the new node as the tail if the list is currently empty + self.tail = new_node + +# add_to_tail performance: + def add_to_tail(self, value): + new_node = Node(value) + if not self.head: + # set the new node as the head if the list is currently empty + self.head = new_node + self.tail = new_node + else: + self.tail.set_next(new_node) + self.tail = new_node + +# remove_head performance: + def remove_head(self): + if not self.head: + # the list is already empty + return None + + removed_value = self.head.get_value() + self.head = self.head.next + if not self.head: + # the list is now empty as the one and only item was removed + self.tail = None + return removed_value + +# remove tail performance: + def remove_tail(self): + if not self.head: + # the list is already empty + return None + + curr = self.head + prev = curr + while curr.get_next != None: + prev = curr + curr = curr.get_next() + + prev.set_next(None) + self.tail = prev + return curr + +# get_max performance: + def get_max(self): + if not self.head: + return None + + curr = self.head + max_value = curr.get_value() + while curr != None: + max_value = max(max_value, curr.get_value()) + curr = curr.get_next() + return max_value + +# contains performance: + def contains(self, value): + curr = self.head + while curr != None: + if curr.get_value() is value: + return True + curr = curr.get_next() + return False From e8aaffe18d6704af5e2c91347e4f9eda6d7692d9 Mon Sep 17 00:00:00 2001 From: Christian Lorenzo Date: Wed, 16 Sep 2020 21:12:03 -0700 Subject: [PATCH 05/10] Update singly_linked_list.py Updated Singly Linked list --- singly_linked_list/singly_linked_list.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/singly_linked_list/singly_linked_list.py b/singly_linked_list/singly_linked_list.py index 09cd067c5f..7aeb8e33bc 100644 --- a/singly_linked_list/singly_linked_list.py +++ b/singly_linked_list/singly_linked_list.py @@ -71,15 +71,15 @@ def remove_tail(self): # the list is already empty return None - curr = self.head - prev = curr - while curr.get_next != None: + curr = self.head prev = curr - curr = curr.get_next() + while curr.get_next != None: + prev = curr + curr = curr.get_next() - prev.set_next(None) - self.tail = prev - return curr + prev.set_next(None) + self.tail = prev + return curr # get_max performance: def get_max(self): From b26285fb44a1481975d4d9ca32974bde9befde25 Mon Sep 17 00:00:00 2001 From: Christian Lorenzo Date: Wed, 16 Sep 2020 23:06:26 -0700 Subject: [PATCH 06/10] Finished HW. Home project finished. --- queue/queue.py | 35 +++++++- queue/singly_linked_list.py | 101 ++++++++++++++++++++++ singly_linked_list/singly_linked_list.py | 42 +++++----- stack/singly_linked_list.py | 102 +++++++++++++++++++++++ stack/stack.py | 48 ++++++++++- 5 files changed, 300 insertions(+), 28 deletions(-) create mode 100644 queue/singly_linked_list.py create mode 100644 stack/singly_linked_list.py diff --git a/queue/queue.py b/queue/queue.py index d345aa37f5..4c29b2b0b1 100644 --- a/queue/queue.py +++ b/queue/queue.py @@ -13,21 +13,50 @@ Stretch: What if you could only use instances of your Stack class to implement the Queue? What would that look like? How many Stacks would you need? Try it! """ + +from singly_linked_list import LinkedList + +# 1 Queue (using an array) +# class Queue: +# def __init__(self): +# self.size = 0 +# self.storage = [] + +# # len performance: +# def __len__(self): +# return self.size + +# # enqueue performance: O(1) +# def enqueue(self, value): +# self.storage.append(value) +# self.size += 1 + +# # dequeue performance: O(1) +# def dequeue(self): +# if self.size == 0: +# return None +# else: +# self.size -= 1 +# return self.storage.pop(0) + + + +# # 2 Queue (using a linked list) class Queue: def __init__(self): self.size = 0 self.storage = LinkedList() def __len__(self): - self.size + return self.size def enqueue(self, value): self.storage.add_to_tail(value) self.size += 1 def dequeue(self): - if self.isEmpty() == 0: + if self.size == 0: return None else: self.size -= 1 - return self.storage.remove_head() + return self.storage.remove_head() \ No newline at end of file diff --git a/queue/singly_linked_list.py b/queue/singly_linked_list.py new file mode 100644 index 0000000000..65957cfd57 --- /dev/null +++ b/queue/singly_linked_list.py @@ -0,0 +1,101 @@ +class Node: + def __init__(self, value=None, next=None): + self.value = value + self.next = next + + def __repr__(self): + return self.value + + def get_value(self): + return self.value + + def get_next(self): + return self.next + + def set_next(self, new_next): + self.next = new_next + +# Singly list + +class LinkedList: + def __init__(self): + self.head = None + self.tail = None + + def __repr__(self): + node = self.head + nodes = [] + while node is not None: + nodes.append(node.data) + node = node.next + nodes.append("None") + return " -> ".join(nodes) + +# add_to_head performance: + def add_to_head(self, value): + new_node = Node(value, self.head) + self.head = new_node + if not self.tail: + # set the new node as the tail if the list is currently empty + self.tail = new_node + +# add_to_tail performance: + def add_to_tail(self, value): + new_node = Node(value) + if not self.head: + # set the new node as the head if the list is currently empty + self.head = new_node + self.tail = new_node + else: + self.tail.set_next(new_node) + self.tail = new_node + +# remove_head performance: + def remove_head(self): + if not self.head: + # the list is already empty + return None + + removed_value = self.head.get_value() + self.head = self.head.next + if not self.head: + # the list is now empty as the one and only item was removed + self.tail = None + return removed_value + +# remove tail performance: + def remove_tail(self): + if not self.head: + # the list is already empty + return None + + curr = self.head + prev = curr + while curr.get_next() != None: + prev = curr + curr = curr.get_next() + + prev.set_next(None) + self.tail = prev + return curr + +# get_max performance: + def get_max(self): + if not self.head: + return None + + curr = self.head + max_value = curr.get_value() + while curr != None: + max_value = max(max_value, curr.get_value()) + curr = curr.get_next() + return max_value + +# contains performance: + def contains(self, value): + curr = self.head + while curr != None: + if curr.get_value() is value: + return True + curr = curr.get_next() + return False \ No newline at end of file diff --git a/singly_linked_list/singly_linked_list.py b/singly_linked_list/singly_linked_list.py index 7aeb8e33bc..38826072c7 100644 --- a/singly_linked_list/singly_linked_list.py +++ b/singly_linked_list/singly_linked_list.py @@ -4,26 +4,26 @@ class Node: def __init__(self, value=None, next=None): self.value = value self.next = next - + def __repr__(self): return self.value def get_value(self): return self.value - + def get_next(self): return self.next - + def set_next(self, new_next): self.next = new_next -# Singly list +# Singly Linked List class LinkedList: def __init__(self): self.head = None self.tail = None - + def __repr__(self): node = self.head nodes = [] @@ -32,16 +32,16 @@ def __repr__(self): node = node.next nodes.append("None") return " -> ".join(nodes) - -# add_to_head performance: + + # add_to_head performance: O(1) def add_to_head(self, value): new_node = Node(value, self.head) self.head = new_node if not self.tail: # set the new node as the tail if the list is currently empty self.tail = new_node - -# add_to_tail performance: + + # add_to_tail performance: O(1) def add_to_tail(self, value): new_node = Node(value) if not self.head: @@ -52,48 +52,48 @@ def add_to_tail(self, value): self.tail.set_next(new_node) self.tail = new_node -# remove_head performance: + # remove_head performance: O(1) def remove_head(self): if not self.head: # the list is already empty return None - + removed_value = self.head.get_value() self.head = self.head.next if not self.head: # the list is now empty as the one and only item was removed - self.tail = None + self.tail = None return removed_value -# remove tail performance: + # remove_tail performance: O(n) def remove_tail(self): if not self.head: # the list is already empty return None - + curr = self.head prev = curr - while curr.get_next != None: + while curr.get_next() != None: prev = curr curr = curr.get_next() - + prev.set_next(None) self.tail = prev return curr - -# get_max performance: + + # get_max performance: O(n) def get_max(self): if not self.head: return None - + curr = self.head max_value = curr.get_value() while curr != None: max_value = max(max_value, curr.get_value()) curr = curr.get_next() return max_value - -# contains performance: + + # contains performance: O(n) def contains(self, value): curr = self.head while curr != None: diff --git a/stack/singly_linked_list.py b/stack/singly_linked_list.py new file mode 100644 index 0000000000..acfb87b0fb --- /dev/null +++ b/stack/singly_linked_list.py @@ -0,0 +1,102 @@ +# Node +class Node: + def __init__(self, value=None, next=None): + self.value = value + self.next = next + + def __repr__(self): + return self.value + + def get_value(self): + return self.value + + def get_next(self): + return self.next + + def set_next(self, new_next): + self.next = new_next + +# Singly list + +class LinkedList: + def __init__(self): + self.head = None + self.tail = None + + def __repr__(self): + node = self.head + nodes = [] + while node is not None: + nodes.append(node.data) + node = node.next + nodes.append("None") + return " -> ".join(nodes) + +# add_to_head performance: + def add_to_head(self, value): + new_node = Node(value, self.head) + self.head = new_node + if not self.tail: + # set the new node as the tail if the list is currently empty + self.tail = new_node + +# add_to_tail performance: + def add_to_tail(self, value): + new_node = Node(value) + if not self.head: + # set the new node as the head if the list is currently empty + self.head = new_node + self.tail = new_node + else: + self.tail.set_next(new_node) + self.tail = new_node + +# remove_head performance: + def remove_head(self): + if not self.head: + # the list is already empty + return None + + removed_value = self.head.get_value() + self.head = self.head.next + if not self.head: + # the list is now empty as the one and only item was removed + self.tail = None + return removed_value + +# remove tail performance: + def remove_tail(self): + if not self.head: + # the list is already empty + return None + + curr = self.head + prev = curr + while curr.get_next() != None: + prev = curr + curr = curr.get_next() + + prev.set_next(None) + self.tail = prev + return curr + +# get_max performance: + def get_max(self): + if not self.head: + return None + + curr = self.head + max_value = curr.get_value() + while curr != None: + max_value = max(max_value, curr.get_value()) + curr = curr.get_next() + return max_value + +# contains performance: + def contains(self, value): + curr = self.head + while curr != None: + if curr.get_value() is value: + return True + curr = curr.get_next() + return False \ No newline at end of file diff --git a/stack/stack.py b/stack/stack.py index 6e6d660ac7..67ab6f78b5 100644 --- a/stack/stack.py +++ b/stack/stack.py @@ -10,16 +10,56 @@ 3. What is the difference between using an array vs. a linked list when implementing a Stack? """ +import sys +sys.path.append('singly_linked_list') +from singly_linked_list import LinkedList + +# Stack (Using an array): +# class Stack: +# def __init__(self): +# self.size = 0 +# self.storage = [] + +# # le performance: O(1) +# def __len__(self): +# return self.size + +# # pushing performance: O(1) +# def push(self, value): +# self.storage.append(value) +# self.size += 1 + +# # pop performance: O(1) +# def pop(self): +# if self.size == 0: +# return None +# else: +# self.size -= 1 +# return self.storage.pop() + + +# Stack (using a linked list): class Stack: def __init__(self): self.size = 0 - # self.storage = ? + self.storage = LinkedList() + + def isEmpty(self): + return self.size == 0 + # len performance: O(1) def __len__(self): - pass + return self.size + # push performance: O(1) def push(self, value): - pass + self.storage.add_to_head(value) + self.size += 1 + # pop performance: O(1) def pop(self): - pass + if self.size == 0: + return None + else: + self.size -= 1 + return self.storage.remove_head() From 4c8eff148aad0da6d190ae6bb8343f409821351a Mon Sep 17 00:00:00 2001 From: Christian Lorenzo Date: Wed, 16 Sep 2020 23:20:05 -0700 Subject: [PATCH 07/10] Update singly_linked_list.py Updated Singly linked list. All tests passing. --- singly_linked_list/singly_linked_list.py | 56 +++++++++++++----------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/singly_linked_list/singly_linked_list.py b/singly_linked_list/singly_linked_list.py index 38826072c7..243bb7eac1 100644 --- a/singly_linked_list/singly_linked_list.py +++ b/singly_linked_list/singly_linked_list.py @@ -4,26 +4,26 @@ class Node: def __init__(self, value=None, next=None): self.value = value self.next = next - + def __repr__(self): return self.value def get_value(self): return self.value - + def get_next(self): return self.next - + def set_next(self, new_next): self.next = new_next -# Singly Linked List +# Singly list class LinkedList: def __init__(self): self.head = None self.tail = None - + def __repr__(self): node = self.head nodes = [] @@ -32,16 +32,16 @@ def __repr__(self): node = node.next nodes.append("None") return " -> ".join(nodes) - - # add_to_head performance: O(1) + +# add_to_head performance: def add_to_head(self, value): new_node = Node(value, self.head) self.head = new_node if not self.tail: # set the new node as the tail if the list is currently empty self.tail = new_node - - # add_to_tail performance: O(1) + +# add_to_tail performance: def add_to_tail(self, value): new_node = Node(value) if not self.head: @@ -52,48 +52,52 @@ def add_to_tail(self, value): self.tail.set_next(new_node) self.tail = new_node - # remove_head performance: O(1) +# remove_head performance: def remove_head(self): if not self.head: # the list is already empty return None - + removed_value = self.head.get_value() self.head = self.head.next if not self.head: # the list is now empty as the one and only item was removed - self.tail = None + self.tail = None return removed_value - # remove_tail performance: O(n) +# remove tail performance: def remove_tail(self): if not self.head: # the list is already empty return None - + if self.head is self.tail: + value = self.head.get_value() + self.head = None + self.tail = None + return value + curr = self.head - prev = curr - while curr.get_next() != None: - prev = curr + + while curr.get_next() is not self.tail: curr = curr.get_next() - - prev.set_next(None) - self.tail = prev - return curr - - # get_max performance: O(n) + + value = self.tail.get_value() + self.tail = curr + return value + +# get_max performance: def get_max(self): if not self.head: return None - + curr = self.head max_value = curr.get_value() while curr != None: max_value = max(max_value, curr.get_value()) curr = curr.get_next() return max_value - - # contains performance: O(n) + +# contains performance: def contains(self, value): curr = self.head while curr != None: From e392e28602e7857e0cbc9dbbd08024ceab805cc1 Mon Sep 17 00:00:00 2001 From: Christian Lorenzo Date: Sat, 19 Sep 2020 23:01:19 -0700 Subject: [PATCH 08/10] Doubly Linked List Ready --- doubly_linked_list/doubly_linked_list.py | 102 +++++++++++++++++++++-- 1 file changed, 94 insertions(+), 8 deletions(-) diff --git a/doubly_linked_list/doubly_linked_list.py b/doubly_linked_list/doubly_linked_list.py index 6f91b43a9b..13ee23250e 100644 --- a/doubly_linked_list/doubly_linked_list.py +++ b/doubly_linked_list/doubly_linked_list.py @@ -7,6 +7,24 @@ def __init__(self, value, prev=None, next=None): self.prev = prev self.value = value self.next = next + + def __repr__(self): + return self.value + + def get_value(self): + return self.value + + def get_next(self): + return self.next + + def get_prev(self): + return self.prev + + def set_next(self, new_next): + self.next = new_next + + def set_prev(self, new_prev): + self.prev = new_prev """ Our doubly-linked list class. It holds references to @@ -27,7 +45,18 @@ def __len__(self): the old head node's previous pointer accordingly. """ def add_to_head(self, value): - pass + self.add_node_to_head(ListNode(value)) + + def add_node_to_head(self, node): + self.length += 1 + node.set_prev(None) + node.set_next(self.head) + if self.head: + self.head.set_prev(node) + else: + # the list is currently empty + self.tail = node + self.head = node """ Removes the List's current head node, making the @@ -35,7 +64,20 @@ def add_to_head(self, value): Returns the value of the removed Node. """ def remove_from_head(self): - pass + if not self.head: + # the is already empty + return None + + self.length -= 1 + removed_value = self.head.get_value() + self.head = self.head.get_next() + if self.head: + self.head.set_prev(None) + else: + # the list is now empty + self.tail = None + return removed_value + """ Wraps the given value in a ListNode and inserts it @@ -43,7 +85,18 @@ def remove_from_head(self): the old tail node's next pointer accordingly. """ def add_to_tail(self, value): - pass + self.add_node_to_tail(ListNode(value)) + + def add_node_to_tail(self, node): + self.length += 1 + node.set_prev(self.tail) + node.set_next(None) + if self.tail: + self.tail.set_next(node) + else: + # the list is currently empty + self.head = node + self.tail = node """ Removes the List's current tail node, making the @@ -51,32 +104,65 @@ def add_to_tail(self, value): Returns the value of the removed Node. """ def remove_from_tail(self): - pass + if not self.head: + # the list is already empty + return None + + self.length -= 1 + removed_value = self.tail.get_value() + self.tail = self.tail.get_prev() + if self.tail: + self.tail.set_next(None) + else: + # the list is now empty + self.head = None + return removed_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): - pass + if node is not self.head: + self.delete(node) + self.add_node_to_head(node) """ 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): - pass + if node is not self.tail: + self.delete(node) + self.add_node_to_tail(node) """ Deletes the input node from the List, preserving the order of the other elements of the List. """ def delete(self, node): - pass + if node is self.head: + self.remove_from_head() + elif node is self.tail: + self.remove_from_tail() + else: + self.length -= 1 + prev_node = node.get_prev() + next_node = node.get_next() + prev_node.set_next(next_node) + next_node.set_prev(prev_node) """ Finds and returns the maximum value of all the nodes in the List. """ def get_max(self): - pass \ No newline at end of file + if not self.head: + return None + + curr = self.head + max_value = curr.get_value() + while curr != None: + max_value = max(max_value, curr.get_value()) + curr = curr.get_next() + return max_value \ No newline at end of file From 2d9a31b31a778ca5b309e5dd3bcabe5b32216337 Mon Sep 17 00:00:00 2001 From: Christian Lorenzo Date: Tue, 22 Sep 2020 22:44:54 -0700 Subject: [PATCH 09/10] Make changes on the test file and on the binary file. Tests are not running yet. Getting one error on line 100 from the test file. --- binary_search_tree/binary_search_tree.py | 84 +++++++++++++++++-- binary_search_tree/test_binary_search_tree.py | 4 +- 2 files changed, 78 insertions(+), 10 deletions(-) diff --git a/binary_search_tree/binary_search_tree.py b/binary_search_tree/binary_search_tree.py index d33bb091f7..8e536b8b8d 100644 --- a/binary_search_tree/binary_search_tree.py +++ b/binary_search_tree/binary_search_tree.py @@ -11,7 +11,66 @@ """ import sys -sys.path.extend(["queue", "stack", "binary_search_tree"]) +sys.path.extend(['queue', 'stack', 'binary_search_tree', 'binary_search_tree_displayer']) +from queue import Queue +from stack import Stack +# from binary_search_tree_displayer import BSTNodeDisplayer + +class BSTDisplayer: + def __init__(self, bst): + self.bst = bst + + def display(self): + lines, *_ = self._display_aux(self.bst) + for line in lines: + print(line) + + def _display_aux(self, bst_node): + """Returns list of strings, width, height, and horizontal coordinate of the root.""" + # No child. + if bst_node.right is None and bst_node.left is None: + line = '%s' % bst_node.value + width = len(line) + height = 1 + middle = width // 2 + return [line], width, height, middle + + # Only left child. + if bst_node.right is None: + lines, n, p, x = self._display_aux(bst_node.left) + s = '%s' % bst_node.value + u = len(s) + first_line = (x + 1) * ' ' + (n - x - 1) * '_' + s + second_line = x * ' ' + '/' + (n - x - 1 + u) * ' ' + shifted_lines = [line + u * ' ' for line in lines] + return [first_line, second_line] + shifted_lines, n + u, p + 2, n + u // 2 + + # Only right child. + if bst_node.left is None: + lines, n, p, x = self._display_aux(bst_node.right) + s = '%s' % bst_node.value + u = len(s) + first_line = s + x * '_' + (n - x) * ' ' + second_line = (u + x) * ' ' + '\\' + (n - x - 1) * ' ' + shifted_lines = [u * ' ' + line for line in lines] + return [first_line, second_line] + shifted_lines, n + u, p + 2, u // 2 + + # Two children. + left, n, p, x = self._display_aux(bst_node.left) + right, m, q, y = self._display_aux(bst_node.right) + s = '%s' % bst_node.value + u = len(s) + first_line = (x + 1) * ' ' + (n - x - 1) * '_' + s + y * '_' + (m - y) * ' ' + second_line = x * ' ' + '/' + (n - x - 1 + u + y) * ' ' + '\\' + (m - y - 1) * ' ' + if p < q: + left += [n * ' '] * (q - p) + elif q < p: + right += [m * ' '] * (p - q) + zipped_lines = zip(left, right) + lines = [first_line, second_line] + [a + u * ' ' + b for a, b in zipped_lines] + return lines, n + m + u, max(p, q) + 2, n + u // 2 + +# ================================================================= class BSTNode: def __init__(self, value): @@ -71,7 +130,7 @@ def in_order_print(self): # Print the value of every node, starting with the given node, # in an iterative breadth first traversal - def bft_print(self): + def bft_print(self, node): queue = Queue() queue.put(node) while not queue.empty(): @@ -84,10 +143,10 @@ def bft_print(self): # Print the value of every node, starting with the given node, # in an iterative depth first traversal - def dft_print(self): + def dft_print(self, node): stack = Stack() stack.push(node) - while not stack.is Empty(): + while not stack.isEmpty(): node = stack.pop() print(node.value) if node.right: @@ -110,12 +169,19 @@ def pre_order_dft(self): # Print Post-order recursive DFT def post_order_dft(self): - pass + if not self: + return + if self.left: + self.left.post_order_dft() + if self.right: + self.right.post_order_dft() + print(self.value) """ This code is necessary for testing the `print` methods """ bst = BSTNode(1) +bst_displayer = BSTDisplayer(bst) bst.insert(8) bst.insert(5) @@ -125,13 +191,15 @@ def post_order_dft(self): bst.insert(4) bst.insert(2) -bst.bft_print() -bst.dft_print() +bst_displayer.display() + +#bst.bft_print(bst) +#bst.dft_print(bst) print("elegant methods") print("pre order") bst.pre_order_dft() print("in order") -bst.in_order_dft() +bst.in_order_print() print("post order") bst.post_order_dft() diff --git a/binary_search_tree/test_binary_search_tree.py b/binary_search_tree/test_binary_search_tree.py index 0a0cee5911..311035de13 100644 --- a/binary_search_tree/test_binary_search_tree.py +++ b/binary_search_tree/test_binary_search_tree.py @@ -83,13 +83,13 @@ def test_print_traversals(self): self.assertEqual(output, "1\n2\n3\n4\n5\n6\n7\n8\n") sys.stdout = io.StringIO() - self.bst.bft_print() + 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.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") From 15ce4872c1400ef397672933df848e07aaabe8cb Mon Sep 17 00:00:00 2001 From: Christian Lorenzo Date: Wed, 23 Sep 2020 21:09:47 -0700 Subject: [PATCH 10/10] Finished homework with Stretch goals --- binary_search_tree/binary_search_tree.py | 177 +++++++++++++++++++++-- doubly_linked_list/doubly_linked_list.py | 2 +- 2 files changed, 167 insertions(+), 12 deletions(-) diff --git a/binary_search_tree/binary_search_tree.py b/binary_search_tree/binary_search_tree.py index 8e536b8b8d..10f871d491 100644 --- a/binary_search_tree/binary_search_tree.py +++ b/binary_search_tree/binary_search_tree.py @@ -12,8 +12,8 @@ import sys sys.path.extend(['queue', 'stack', 'binary_search_tree', 'binary_search_tree_displayer']) -from queue import Queue -from stack import Stack +# from queue import Queue +#from stack import Stack # from binary_search_tree_displayer import BSTNodeDisplayer class BSTDisplayer: @@ -72,6 +72,155 @@ def _display_aux(self, bst_node): # ================================================================= +class Node: + def __init__(self, value=None, next=None): + self.value = value + self.next = next + + def __repr__(self): + return self.value + + def get_value(self): + return self.value + + def get_next(self): + return self.next + + def set_next(self, new_next): + self.next = new_next + +# Singly list + +class LinkedList: + def __init__(self): + self.head = None + self.tail = None + + def __repr__(self): + node = self.head + nodes = [] + while node is not None: + nodes.append(node.data) + node = node.next + nodes.append("None") + return " -> ".join(nodes) + +# add_to_head performance: + def add_to_head(self, value): + new_node = Node(value, self.head) + self.head = new_node + if not self.tail: + # set the new node as the tail if the list is currently empty + self.tail = new_node + +# add_to_tail performance: + def add_to_tail(self, value): + new_node = Node(value) + if not self.head: + # set the new node as the head if the list is currently empty + self.head = new_node + self.tail = new_node + else: + self.tail.set_next(new_node) + self.tail = new_node + +# remove_head performance: + def remove_head(self): + if not self.head: + # the list is already empty + return None + + removed_value = self.head.get_value() + self.head = self.head.next + if not self.head: + # the list is now empty as the one and only item was removed + self.tail = None + return removed_value + +# remove tail performance: + def remove_tail(self): + if not self.head: + # the list is already empty + return None + + curr = self.head + prev = curr + while curr.get_next() != None: + prev = curr + curr = curr.get_next() + + prev.set_next(None) + self.tail = prev + return curr + +# get_max performance: + def get_max(self): + if not self.head: + return None + + curr = self.head + max_value = curr.get_value() + while curr != None: + max_value = max(max_value, curr.get_value()) + curr = curr.get_next() + return max_value + +# contains performance: + def contains(self, value): + curr = self.head + while curr != None: + if curr.get_value() is value: + return True + curr = curr.get_next() + return False + +# # 2 Queue (using a linked list) +class Queue: + def __init__(self): + self.size = 0 + self.storage = LinkedList() + + def __len__(self): + return self.size + + def enqueue(self, value): + self.storage.add_to_tail(value) + self.size += 1 + + def dequeue(self): + if self.size == 0: + return None + else: + self.size -= 1 + return self.storage.remove_head() + + +class Stack: + def __init__(self): + self.size = 0 + self.storage = LinkedList() + + def isEmpty(self): + return self.size == 0 + + # len performance: O(1) + def __len__(self): + return self.size + + # push performance: O(1) + def push(self, value): + self.storage.add_to_head(value) + self.size += 1 + + # pop performance: O(1) + def pop(self): + if self.size == 0: + return None + else: + self.size -= 1 + return self.storage.remove_head() + + class BSTNode: def __init__(self, value): self.value = value @@ -80,9 +229,14 @@ def __init__(self, value): # Insert the given value into the tree def insert(self, value): + #check if the new node's value is less than the current node's value. if value < self.value: + #if there's no left child alredy here if self.left is None: + #add new node to the left + #create a BSTNode and encapsulate the value in it then set it to the left self.left = BSTNode(value) + #otherwise call insert on the left node else: self.left.insert(value) elif value >= self.value: @@ -94,6 +248,7 @@ def insert(self, value): # Return True if the tree contains the value # False if it does not def contains(self, target): + # if the value of the current node matches the target if target == self.value: return True elif target < self.value: @@ -132,14 +287,14 @@ def in_order_print(self): # in an iterative breadth first traversal def bft_print(self, node): queue = Queue() - queue.put(node) - while not queue.empty(): - node = queue.get() + queue.enqueue(node) + while queue.size > 0: + node = queue.dequeue() print(node.value) if node.left: - queue.put(node.left) + queue.enqueue(node.left) if node.right: - queue.put(node.right) + queue.enqueue(node.right) # Print the value of every node, starting with the given node, # in an iterative depth first traversal @@ -164,8 +319,8 @@ def pre_order_dft(self): print(self.value) if self.left: self.left.pre_order_dft() - if self.right: - self.right.pre_order_dft() + if self.right: + self.right.pre_order_dft() # Print Post-order recursive DFT def post_order_dft(self): @@ -193,8 +348,8 @@ def post_order_dft(self): bst_displayer.display() -#bst.bft_print(bst) -#bst.dft_print(bst) +bst.bft_print(bst) +bst.dft_print(bst) print("elegant methods") print("pre order") diff --git a/doubly_linked_list/doubly_linked_list.py b/doubly_linked_list/doubly_linked_list.py index 13ee23250e..f7e7b764a3 100644 --- a/doubly_linked_list/doubly_linked_list.py +++ b/doubly_linked_list/doubly_linked_list.py @@ -49,7 +49,7 @@ def add_to_head(self, value): def add_node_to_head(self, node): self.length += 1 - node.set_prev(None) + node.set_prev(None) node.set_next(self.head) if self.head: self.head.set_prev(node)