From caa7a228831e8c5c160ba0967a42c198bf01e643 Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Tue, 15 Sep 2020 21:34:32 -0600 Subject: [PATCH 01/19] Update singly_linked_list.py --- singly_linked_list/singly_linked_list.py | 117 +++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/singly_linked_list/singly_linked_list.py b/singly_linked_list/singly_linked_list.py index e69de29bb2..47ca714c64 100644 --- a/singly_linked_list/singly_linked_list.py +++ b/singly_linked_list/singly_linked_list.py @@ -0,0 +1,117 @@ +# linear data structure made up of nodes and refs to the next node + +# lets make some node class +class Node: + def __init__(self, value, next_node = None): + self.value = value + self.next_node = next_node + + def get_value(self): + """ + Method to get the value of a node + """ + return self.value + + def get_next(self): + """ + Method to get the next node + """ + return self.next_node + + def set_next(self, new_next): + """ + Method to update the node's "next_node" + """ + self.next_node = new_next + + +# now lets think of how we can make nodes interact in a way that consolidates their pieces together + +# lets make a LinkedList class +# think of the idea of having a head and a tail like a snake +# where the snake can grow based upon having more links in it + +class LinkedList: + def __init__(self): + self.head = None + self.tail = None + + def add_to_tail(self, value): + # wrap the value in a new Node + new_node = Node(value) + + # check if the linked list is empty + if self.head == None and self.tail == None: + # set the head and tail to the new node + self.head = new_node + self.tail = new_node + # otherwise the list must have a head and tail + else: + # update the last node's "next_node" to the new node + self.tail.set_next(new_node) # (Last node in chain).next_node = new_node + # update the "self.tail" to point to the new node that we just added + self.tail = new_node + + def remove_tail(self): + """ + Remove the last node in the chain and return its value + """ + # check for empty list + if self.head == None and self.tail == None: + # if true return None + return None + # check if there's only one node + if self.head == self.tail: + # store the value of the node that we are going to remove + value = self.tail.get_value() + # remove the node + # setting the head and the tail to None + self.head = None + self.tail = None + # return the stored value of the Node + return value + # otherwise + else: + # store the value of the node that we are going to remove + value = self.tail.get_value() + # we need to set the "self.tail" to the second to last Node + # we can only do this by traversing the whole list from beginning to end + + # starting from the head + current_node = self.head + # keep iterating until the node after "current_node" is the tail + while current_node.get_next() != self.tail: + # keep looping + current_node = current_node.get_next() + + # set the "self.tail" to the current_node + self.tail = current_node + + # set the new tail's "next_node" to None + self.tail.next_node = None + + # return Value + return value + + def remove_head(self): + # check for empty list + if self.head == None and self.tail == None: + # if true return None + return None + if self.head == self.tail: + # store the value of the node that we are going to remove + value = self.head.get_value() + # remove the node + # setting the head and the tail to None + self.head = None + self.tail = None + # return the stored value of the Node + return value + else: + # store the head's old value + value = self.head.get_value() + # set self.head to the old head's next + self.head = self.head.get_next() + # retun the value + return value + From 86e418800d02c8c84df54a5e83d69fa354e31eb1 Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Wed, 16 Sep 2020 19:36:20 -0600 Subject: [PATCH 02/19] Create singly_linked_list.py --- queue/singly_linked_list.py | 117 ++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 queue/singly_linked_list.py diff --git a/queue/singly_linked_list.py b/queue/singly_linked_list.py new file mode 100644 index 0000000000..24e3891c76 --- /dev/null +++ b/queue/singly_linked_list.py @@ -0,0 +1,117 @@ +# linear data structure made up of nodes and refs to the next node + +# lets make some node class +class Node: + def __init__(self, value, next_node = None): + self.value = value + self.next_node = next_node + + def get_value(self): + """ + Method to get the value of a node + """ + return self.value + + def get_next(self): + """ + Method to get the next node + """ + return self.next_node + + def set_next(self, new_next): + """ + Method to update the node's "next_node" + """ + self.next_node = new_next + + +# now lets think of how we can make nodes interact in a way that consolidates their pieces together + +# lets make a LinkedList class +# think of the idea of having a head and a tail like a snake +# where the snake can grow based upon having more links in it + +class LinkedList: + def __init__(self): + self.head = None + self.tail = None + + def add_to_tail(self, value): + # wrap the value in a new Node + new_node = Node(value) + + # check if the linked list is empty + if self.head == None and self.tail == None: + # set the head and tail to the new node + self.head = new_node + self.tail = new_node + # otherwise the list must have a head and tail + else: + # update the last node's "next_node" to the new node + self.tail.set_next(new_node) # (Last node in chain).next_node = new_node + # update the "self.tail" to point to the new node that we just added + self.tail = new_node + + def remove_tail(self): + """ + Remove the last node in the chain and return its value + """ + # check for empty list + if self.head == None and self.tail == None: + # if true return None + return None + # check if there's only one node + if self.head == self.tail: + # store the value of the node that we are going to remove + value = self.tail.get_value() + # remove the node + # setting the head and the tail to None + self.head = None + self.tail = None + # return the stored value of the Node + return value + # otherwise + else: + # store the value of the node that we are going to remove + value = self.tail.get_value() + # we need to set the "self.tail" to the second to last Node + # we can only do this by traversing the whole list from beginning to end + + # starting from the head + current_node = self.head + # keep iterating until the node after "current_node" is the tail + while current_node.get_next() != self.tail: + # keep looping + current_node = current_node.get_next() + + # set the "self.tail" to the current_node + self.tail = current_node + + # set the new tail's "next_node" to None + self.tail.next_node = None + + # return Value + return value + + def remove_head(self): + # check for empty list + if self.head == None and self.tail == None: + # if true return None + return None + if self.head == self.tail: + # store the value of the node that we are going to remove + value = self.head.get_value() + # remove the node + # setting the head and the tail to None + self.head = None + self.tail = None + # return the stored value of the Node + return value + else: + # store the head's old value + value = self.head.get_value() + # set self.head to the old head's next + self.head = self.head.get_next() + # retun the value + return value + From 8c5de60fdf5b2170f774bfce8d9d7d6b935122f5 Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Wed, 16 Sep 2020 19:36:47 -0600 Subject: [PATCH 03/19] Updated Queue data-structure --- queue/queue.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/queue/queue.py b/queue/queue.py index 0d2599ded7..45e89a32dd 100644 --- a/queue/queue.py +++ b/queue/queue.py @@ -13,16 +13,25 @@ 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 Node, LinkedList + class Queue: def __init__(self): self.size = 0 - # self.storage = ? + self.storage = LinkedList() def __len__(self): - pass + return self.size def enqueue(self, value): - pass + self.storage.add_to_tail(value) + self.size += 1 def dequeue(self): - pass + if self.size == 0: + return + else: + dequeued_node = self.storage.remove_head() + self.size -= 1 + return dequeued_node From 70fb0eea8f8b0de9b33c346bf83b37ad5dc9c4f1 Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Wed, 16 Sep 2020 19:37:22 -0600 Subject: [PATCH 04/19] Create singly_linked_list.py --- stack/singly_linked_list.py | 117 ++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 stack/singly_linked_list.py diff --git a/stack/singly_linked_list.py b/stack/singly_linked_list.py new file mode 100644 index 0000000000..24e3891c76 --- /dev/null +++ b/stack/singly_linked_list.py @@ -0,0 +1,117 @@ +# linear data structure made up of nodes and refs to the next node + +# lets make some node class +class Node: + def __init__(self, value, next_node = None): + self.value = value + self.next_node = next_node + + def get_value(self): + """ + Method to get the value of a node + """ + return self.value + + def get_next(self): + """ + Method to get the next node + """ + return self.next_node + + def set_next(self, new_next): + """ + Method to update the node's "next_node" + """ + self.next_node = new_next + + +# now lets think of how we can make nodes interact in a way that consolidates their pieces together + +# lets make a LinkedList class +# think of the idea of having a head and a tail like a snake +# where the snake can grow based upon having more links in it + +class LinkedList: + def __init__(self): + self.head = None + self.tail = None + + def add_to_tail(self, value): + # wrap the value in a new Node + new_node = Node(value) + + # check if the linked list is empty + if self.head == None and self.tail == None: + # set the head and tail to the new node + self.head = new_node + self.tail = new_node + # otherwise the list must have a head and tail + else: + # update the last node's "next_node" to the new node + self.tail.set_next(new_node) # (Last node in chain).next_node = new_node + # update the "self.tail" to point to the new node that we just added + self.tail = new_node + + def remove_tail(self): + """ + Remove the last node in the chain and return its value + """ + # check for empty list + if self.head == None and self.tail == None: + # if true return None + return None + # check if there's only one node + if self.head == self.tail: + # store the value of the node that we are going to remove + value = self.tail.get_value() + # remove the node + # setting the head and the tail to None + self.head = None + self.tail = None + # return the stored value of the Node + return value + # otherwise + else: + # store the value of the node that we are going to remove + value = self.tail.get_value() + # we need to set the "self.tail" to the second to last Node + # we can only do this by traversing the whole list from beginning to end + + # starting from the head + current_node = self.head + # keep iterating until the node after "current_node" is the tail + while current_node.get_next() != self.tail: + # keep looping + current_node = current_node.get_next() + + # set the "self.tail" to the current_node + self.tail = current_node + + # set the new tail's "next_node" to None + self.tail.next_node = None + + # return Value + return value + + def remove_head(self): + # check for empty list + if self.head == None and self.tail == None: + # if true return None + return None + if self.head == self.tail: + # store the value of the node that we are going to remove + value = self.head.get_value() + # remove the node + # setting the head and the tail to None + self.head = None + self.tail = None + # return the stored value of the Node + return value + else: + # store the head's old value + value = self.head.get_value() + # set self.head to the old head's next + self.head = self.head.get_next() + # retun the value + return value + From 4fe4791dee934e7c0cace3d40255ee7c93209a1f Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Wed, 16 Sep 2020 19:37:43 -0600 Subject: [PATCH 05/19] Updated Stack data-structure --- stack/stack.py | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/stack/stack.py b/stack/stack.py index 6e6d660ac7..ebc3d5aa11 100644 --- a/stack/stack.py +++ b/stack/stack.py @@ -1,7 +1,6 @@ """ A stack is a data structure whose primary purpose is to store and return elements in Last In First Out order. - 1. Implement the Stack class using an array as the underlying storage structure. Make sure the Stack tests pass. 2. Re-implement the Stack class, this time using the linked list implementation @@ -10,16 +9,34 @@ 3. What is the difference between using an array vs. a linked list when implementing a Stack? """ + +from singly_linked_list import Node, LinkedList + class Stack: def __init__(self): self.size = 0 - # self.storage = ? - - def __len__(self): - pass + self.storage = LinkedList() def push(self, value): - pass + self.storage.add_to_tail(value) + self.size += 1 def pop(self): - pass + if self.size == 0: + return + else: + removed_node = self.storage.remove_tail() + self.size -= 1 + return removed_node + + def __len__(self): + return self.size + +# stack = Stack() + +# stack.push(4) +# stack.push(45) +# stack.push(5) +# print(stack.__len__()) +# stack.pop() +# print(stack.__len__()) From dfd132d5f842b932f048ca0cd58a0801e32649c5 Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Thu, 17 Sep 2020 20:35:37 -0600 Subject: [PATCH 06/19] Update doubly_linked_list.py --- doubly_linked_list/doubly_linked_list.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/doubly_linked_list/doubly_linked_list.py b/doubly_linked_list/doubly_linked_list.py index 6f91b43a9b..5e3c2c7ee7 100644 --- a/doubly_linked_list/doubly_linked_list.py +++ b/doubly_linked_list/doubly_linked_list.py @@ -27,7 +27,15 @@ def __len__(self): the old head node's previous pointer accordingly. """ def add_to_head(self, value): - pass + new_node = ListNode(value) + if not self.head and not self.tail: + self.head = new_node + self.tail = new_node + else: + new_node.next = self.head + # set the current head's prev node to the new node + self.head.prev = new_node + self.head = new_node """ Removes the List's current head node, making the @@ -79,4 +87,4 @@ def delete(self, node): in the List. """ def get_max(self): - pass \ No newline at end of file + pass From d6074f813a126816aa3494be2990dbec1011b88c Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Thu, 17 Sep 2020 20:40:01 -0600 Subject: [PATCH 07/19] Update doubly_linked_list.py --- doubly_linked_list/doubly_linked_list.py | 1 + 1 file changed, 1 insertion(+) diff --git a/doubly_linked_list/doubly_linked_list.py b/doubly_linked_list/doubly_linked_list.py index 5e3c2c7ee7..01b2e60cff 100644 --- a/doubly_linked_list/doubly_linked_list.py +++ b/doubly_linked_list/doubly_linked_list.py @@ -28,6 +28,7 @@ def __len__(self): """ def add_to_head(self, value): new_node = ListNode(value) + self.length += 1 if not self.head and not self.tail: self.head = new_node self.tail = new_node From 76a0f355f97a05436422b4f284de7f2246991e2e Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Fri, 18 Sep 2020 10:15:50 -0600 Subject: [PATCH 08/19] Update doubly_linked_list.py --- doubly_linked_list/doubly_linked_list.py | 67 ++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 4 deletions(-) diff --git a/doubly_linked_list/doubly_linked_list.py b/doubly_linked_list/doubly_linked_list.py index 01b2e60cff..da262b5b66 100644 --- a/doubly_linked_list/doubly_linked_list.py +++ b/doubly_linked_list/doubly_linked_list.py @@ -7,6 +7,30 @@ def __init__(self, value, prev=None, next=None): self.prev = prev self.value = value self.next = next + + def get_value(self): + return self.value + + def next_node(self): + if not self.next: + return + else: + return self.next + + def prev_node(self): + if not self.prev: + return + else: + return self.prev + + def delete(self): + if self.prev: + self.prev.next = self.next + if self.next: + self.next.prev = self.prev + self.value = None + self.next = None + self.prev = None """ Our doubly-linked list class. It holds references to @@ -44,7 +68,17 @@ def add_to_head(self, value): Returns the value of the removed Node. """ def remove_from_head(self): - pass + if not self.head: + return "No head in List" + else: + self.length -= 1 + # get the current head + removed_head = self.head + # set the current head's next as the new head + removed_head.next = self.head + # set the new head's prev as None + self.head.prev = None + return removed_head """ Wraps the given value in a ListNode and inserts it @@ -52,7 +86,15 @@ def remove_from_head(self): the old tail node's next pointer accordingly. """ def add_to_tail(self, value): - pass + new_node = ListNode(value) + 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 @@ -60,8 +102,14 @@ def add_to_tail(self, value): Returns the value of the removed Node. """ def remove_from_tail(self): - pass - + if not self.tail: + return "No tail in List" + else: + self.length -= 1 + removed_tail = self.tail + removed_tail.prev = self.tail + self.tail.next = None + return removed_tail """ Removes the input node from its current spot in the List and inserts it as the new head node of the List. @@ -89,3 +137,14 @@ def delete(self, node): """ def get_max(self): pass + +d = DoublyLinkedList() +head = ListNode("head") +tail = ListNode("tail") + +d.add_to_head(head) +d.add_to_tail(tail) +print(d.__len__()) + +print(d.delete(head)) +print(d.__len__()) From ed2469c74ebbd2945b95faa9212098d6da284867 Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Fri, 18 Sep 2020 14:25:35 -0600 Subject: [PATCH 09/19] Update doubly_linked_list.py --- doubly_linked_list/doubly_linked_list.py | 35 +++++++++++++++++++----- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/doubly_linked_list/doubly_linked_list.py b/doubly_linked_list/doubly_linked_list.py index da262b5b66..df329d946d 100644 --- a/doubly_linked_list/doubly_linked_list.py +++ b/doubly_linked_list/doubly_linked_list.py @@ -115,21 +115,39 @@ def remove_from_tail(self): List and inserts it as the new head node of the List. """ def move_to_front(self, node): - pass + new_head_node = node + self.add_to_head(new_head_node) + node.delete() """ 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 + new_tail_node = node + self.add_to_tail(new_tail_node) + node.delete() """ Deletes the input node from the List, preserving the order of the other elements of the List. """ def delete(self, node): - pass + node.delete() + self.length -= 1 + + def get_node_value(self, node): + return node.get_value() + + def get_all_nodes(self): + if not self.head and not self.tail: + print("No nodes in List") + else: + current_node = self.head + while current_node is not self.tail: + print(f"{current_node.get_value().value}") + current_node = current_node.next_node() + print(self.tail.get_value().value) """ Finds and returns the maximum value of all the nodes @@ -140,11 +158,14 @@ def get_max(self): d = DoublyLinkedList() head = ListNode("head") -tail = ListNode("tail") +new_tail = ListNode("new tail") +new_new_tail = ListNode("new new tail") +tail = ListNode("tagil") +new_head = ListNode("new head") d.add_to_head(head) d.add_to_tail(tail) -print(d.__len__()) +d.add_to_tail(new_tail) +d.add_to_head(new_head) -print(d.delete(head)) -print(d.__len__()) +d.get_all_nodes() From 0c5844fff20838e7f76fcb221c9ba62a44d05f2b Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Mon, 21 Sep 2020 19:30:57 -0600 Subject: [PATCH 10/19] Update doubly_linked_list.py --- doubly_linked_list/doubly_linked_list.py | 104 +++++++++++++++-------- 1 file changed, 67 insertions(+), 37 deletions(-) diff --git a/doubly_linked_list/doubly_linked_list.py b/doubly_linked_list/doubly_linked_list.py index df329d946d..8b2bd833ff 100644 --- a/doubly_linked_list/doubly_linked_list.py +++ b/doubly_linked_list/doubly_linked_list.py @@ -12,16 +12,16 @@ def get_value(self): return self.value def next_node(self): - if not self.next: - return - else: + if self.next: return self.next + else: + return None def prev_node(self): - if not self.prev: - return - else: + if self.prev: return self.prev + else: + return None def delete(self): if self.prev: @@ -72,12 +72,14 @@ def remove_from_head(self): return "No head in List" else: self.length -= 1 - # get the current head - removed_head = self.head + # get the old head into a ValueError + removed_head = self.head.get_value() + # get the next head + new_head = self.head.next_node() + # remove the current head + self.head.delete() # set the current head's next as the new head - removed_head.next = self.head - # set the new head's prev as None - self.head.prev = None + self.head = new_head return removed_head """ @@ -106,46 +108,68 @@ def remove_from_tail(self): return "No tail in List" else: self.length -= 1 - removed_tail = self.tail - removed_tail.prev = self.tail - self.tail.next = None + removed_tail = self.tail.get_value() + new_tail = self.tail.prev_node() + self.tail.delete() + self.tail = new_tail return removed_tail """ 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): - new_head_node = node - self.add_to_head(new_head_node) - node.delete() + new_head_value = node.value + if node == self.head: + return + elif node == self.tail: + self.remove_from_tail() + self.add_to_head(new_head_value) + else: + self.delete(node) + self.add_to_head(new_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): - new_tail_node = node - self.add_to_tail(new_tail_node) - node.delete() + new_tail_value = node.value + if node == self.tail: + return + elif node == self.head: + self.remove_from_head() + self.add_to_tail(new_tail_value) + else: + self.delete(node) + self.add_to_tail(new_tail_value) """ Deletes the input node from the List, preserving the order of the other elements of the List. """ def delete(self, node): - node.delete() - self.length -= 1 - - def get_node_value(self, node): - return node.get_value() + if self.length == 0: + return + elif self.length == 1: + self.length -= 1 + node.delete() + self.head = None + self.tail = None + elif node == self.head: + self.remove_from_head() + elif node == self.tail: + self.remove_from_tail() + else: + self.length -= 1 + node.delete() def get_all_nodes(self): if not self.head and not self.tail: print("No nodes in List") else: current_node = self.head - while current_node is not self.tail: - print(f"{current_node.get_value().value}") + while current_node: + print(f"{current_node.value.value}") current_node = current_node.next_node() print(self.tail.get_value().value) @@ -154,18 +178,24 @@ def get_all_nodes(self): in the List. """ def get_max(self): - pass + if self.length == 0: + return None + max_value = self.head.value + current_node = self.head + while current_node: + if current_node.get_value() > max_value: + max_value = current_node.get_value() + current_node = current_node.next_node() + return max_value + d = DoublyLinkedList() -head = ListNode("head") -new_tail = ListNode("new tail") -new_new_tail = ListNode("new new tail") -tail = ListNode("tagil") -new_head = ListNode("new head") +head = ListNode(3) +tail = ListNode(5) + +new_head = ListNode(9) d.add_to_head(head) -d.add_to_tail(tail) -d.add_to_tail(new_tail) d.add_to_head(new_head) - -d.get_all_nodes() +d.add_to_tail(tail) +print(d.get_max()) From c5dc4220b0a7b701b7caec245ae47bdbd3fbc8f3 Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Mon, 21 Sep 2020 20:02:55 -0600 Subject: [PATCH 11/19] deleted dll object instance --- doubly_linked_list/doubly_linked_list.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/doubly_linked_list/doubly_linked_list.py b/doubly_linked_list/doubly_linked_list.py index 8b2bd833ff..bfdf3cde12 100644 --- a/doubly_linked_list/doubly_linked_list.py +++ b/doubly_linked_list/doubly_linked_list.py @@ -187,15 +187,3 @@ def get_max(self): max_value = current_node.get_value() current_node = current_node.next_node() return max_value - - -d = DoublyLinkedList() -head = ListNode(3) -tail = ListNode(5) - -new_head = ListNode(9) - -d.add_to_head(head) -d.add_to_head(new_head) -d.add_to_tail(tail) -print(d.get_max()) From 8bb87178b5cb9fd05342c7a68c7da3114f6f91cc Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Mon, 21 Sep 2020 21:33:00 -0600 Subject: [PATCH 12/19] Added pseudo-code for Binary Search Tree --- binary_search_tree/binary_search_tree.py | 39 ++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/binary_search_tree/binary_search_tree.py b/binary_search_tree/binary_search_tree.py index d80d9f6282..6908ddc575 100644 --- a/binary_search_tree/binary_search_tree.py +++ b/binary_search_tree/binary_search_tree.py @@ -17,15 +17,54 @@ def __init__(self, value): # Insert the given value into the tree def insert(self, value): + + # check if the value is Less than the value of the current node's value + # if there's no left child already there + # add the new node to the left + # create a BSTNode and encapsulate the value in it and then set it to the Left node + # otherwise recursively call insert on left node + # otherwise the value is Greater than or Equal to the value of the current node + # if there's no right child already there + # add the new node to the right + # create a BSTNode and encapsulate the value in it and then set it to the Right node + # otherwise recursively call insert on right node pass # 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 + # return True + # check if the target is Less than the value of the current node's value + # if there's no left child already there + # return False + # otherwise + # return a call of 'contains' on the Left child passing in the target value + # otherwise the target is Greater than to the value of the current node + # if there's no Right child already there + # return False + # otherwise + # return a call of 'contains' on the Right child passing in the target value pass # Return the maximum value found in the tree def get_max(self): + # check for an empty Tree + # return None + + # ** EASY - Recursive ** + # check if there is no node to the Right + # if True return value + # otherwise return a call to get_max on the Right child + + # ** ITERATIVE approach ** + # initialize the max value //self's value + # get a ref to the current node + # Loop while there is still a Node + # if the current value is greater than the max value, update the max value + # move onto the next right node + + # return max value pass # Call the function `fn` on the value of each node From 0d6ef20e3b31e656ed090074d6fd5babace92d0b Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Tue, 22 Sep 2020 10:23:22 -0600 Subject: [PATCH 13/19] Update binary_search_tree.py --- binary_search_tree/binary_search_tree.py | 77 +++++++++++++++++++----- 1 file changed, 61 insertions(+), 16 deletions(-) diff --git a/binary_search_tree/binary_search_tree.py b/binary_search_tree/binary_search_tree.py index 6908ddc575..fe7e7d8bc7 100644 --- a/binary_search_tree/binary_search_tree.py +++ b/binary_search_tree/binary_search_tree.py @@ -17,45 +17,81 @@ def __init__(self, value): # Insert the given value into the tree def insert(self, value): - - # check if the value is Less than the value of the current node's value + # check if the value is Less than the value of the current node's value + if value < self.value: # if there's no left child already there + if not self.left: # add the new node to the left + left_node = BSTNode(value) # create a BSTNode and encapsulate the value in it and then set it to the Left node + self.left = left_node + print(f"inserted {value} to the left") # otherwise recursively call insert on left node + else: + self.left.insert(value) # otherwise the value is Greater than or Equal to the value of the current node + elif value >= self.value: # if there's no right child already there + if not self.right: # add the new node to the right + right_node = BSTNode(value) # create a BSTNode and encapsulate the value in it and then set it to the Right node + self.right = right_node + print(f"inserted {value} to the right") # otherwise recursively call insert on right node - pass + else: + self.right.insert(value) + else: + print("Cannot insert 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 - # check if the target is Less than the value of the current node's value + return True + # check if the target is Less than the value of the current node's value + elif target < self.value: # if there's no left child already there + if not self.left: # return False + return False # otherwise + else: # return a call of 'contains' on the Left child passing in the target value + self.left.contains(target) # otherwise the target is Greater than to the value of the current node + elif target > self.value: # if there's no Right child already there + if not self.right: # return False + return False # otherwise + else: # return a call of 'contains' on the Right child passing in the target value - pass + self.right.contains(target) + else: + print(f"Could not search tree for {target}") + # Return the maximum value found in the tree def get_max(self): # check for an empty Tree + if not self.left and not self.right: # return None + print("empty tree") + return None # ** EASY - Recursive ** # check if there is no node to the Right + if not self.right: # if True return value + print(self.value) + return self.value # otherwise return a call to get_max on the Right child + else: + self.right.get_max() # ** ITERATIVE approach ** # initialize the max value //self's value @@ -69,6 +105,13 @@ def get_max(self): # Call the function `fn` on the value of each node def for_each(self, fn): + # call the function passing in the current node's value + + # if there is a node to the Left + # call the function on the Left value + + # if there is a node to the Right + # call the function on the Right value pass # Part 2 ----------------------- @@ -102,23 +145,25 @@ def post_order_dft(self): """ This code is necessary for testing the `print` methods """ -bst = BSTNode(1) +bst = BSTNode(4) bst.insert(8) bst.insert(5) -bst.insert(7) +bst.insert(74) bst.insert(6) bst.insert(3) bst.insert(4) bst.insert(2) -bst.bft_print() -bst.dft_print() +print(bst.get_max()) + +# bst.bft_print() +# bst.dft_print() -print("elegant methods") -print("pre order") -bst.pre_order_dft() -print("in order") -bst.in_order_dft() -print("post order") -bst.post_order_dft() +# print("elegant methods") +# print("pre order") +# bst.pre_order_dft() +# print("in order") +# bst.in_order_dft() +# print("post order") +# bst.post_order_dft() From fbdd560e179e6ae763693d7799ebe9ef047abdfc Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Tue, 22 Sep 2020 10:31:01 -0600 Subject: [PATCH 14/19] Fixed issue where class methods would not return value --- binary_search_tree/binary_search_tree.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/binary_search_tree/binary_search_tree.py b/binary_search_tree/binary_search_tree.py index fe7e7d8bc7..21128d79c6 100644 --- a/binary_search_tree/binary_search_tree.py +++ b/binary_search_tree/binary_search_tree.py @@ -60,7 +60,7 @@ def contains(self, target): # otherwise else: # return a call of 'contains' on the Left child passing in the target value - self.left.contains(target) + return self.left.contains(target) # otherwise the target is Greater than to the value of the current node elif target > self.value: # if there's no Right child already there @@ -70,7 +70,7 @@ def contains(self, target): # otherwise else: # return a call of 'contains' on the Right child passing in the target value - self.right.contains(target) + return self.right.contains(target) else: print(f"Could not search tree for {target}") @@ -78,7 +78,7 @@ def contains(self, target): # Return the maximum value found in the tree def get_max(self): # check for an empty Tree - if not self.left and not self.right: + if not self.value: # return None print("empty tree") return None @@ -87,11 +87,10 @@ def get_max(self): # check if there is no node to the Right if not self.right: # if True return value - print(self.value) return self.value # otherwise return a call to get_max on the Right child else: - self.right.get_max() + return self.right.get_max() # ** ITERATIVE approach ** # initialize the max value //self's value @@ -101,7 +100,6 @@ def get_max(self): # move onto the next right node # return max value - pass # Call the function `fn` on the value of each node def for_each(self, fn): @@ -149,12 +147,15 @@ def post_order_dft(self): bst.insert(8) bst.insert(5) -bst.insert(74) +bst.insert(7) bst.insert(6) bst.insert(3) bst.insert(4) bst.insert(2) +print(bst.contains(6)) +print(bst.contains(56)) + print(bst.get_max()) # bst.bft_print() From 5b33670b3a15f5925522cea52be9d9ed7cb53020 Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Tue, 22 Sep 2020 12:39:02 -0600 Subject: [PATCH 15/19] MVP - added type validation for insert method --- binary_search_tree/binary_search_tree.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/binary_search_tree/binary_search_tree.py b/binary_search_tree/binary_search_tree.py index 21128d79c6..81884a979d 100644 --- a/binary_search_tree/binary_search_tree.py +++ b/binary_search_tree/binary_search_tree.py @@ -17,6 +17,12 @@ def __init__(self, value): # Insert the given value into the tree def insert(self, value): + # check if value is int + value_type = type(value) + if value_type != int and value_type != float: + print(f"Error: Insert type is {value_type}") + print("type must be 'int'") + return # check if the value is Less than the value of the current node's value if value < self.value: # if there's no left child already there @@ -25,7 +31,6 @@ def insert(self, value): left_node = BSTNode(value) # create a BSTNode and encapsulate the value in it and then set it to the Left node self.left = left_node - print(f"inserted {value} to the left") # otherwise recursively call insert on left node else: self.left.insert(value) @@ -37,12 +42,10 @@ def insert(self, value): right_node = BSTNode(value) # create a BSTNode and encapsulate the value in it and then set it to the Right node self.right = right_node - print(f"inserted {value} to the right") # otherwise recursively call insert on right node else: self.right.insert(value) - else: - print("Cannot insert value") + # Return True if the tree contains the value # False if it does not @@ -104,13 +107,16 @@ def get_max(self): # Call the function `fn` on the value of each node def for_each(self, fn): # call the function passing in the current node's value - + fn(self.value) # if there is a node to the Left + if self.left: # call the function on the Left value - + self.left.for_each(fn) # if there is a node to the Right + else: # call the function on the Right value - pass + self.right.for_each(fn) + # Part 2 ----------------------- @@ -151,7 +157,7 @@ def post_order_dft(self): bst.insert(6) bst.insert(3) bst.insert(4) -bst.insert(2) +bst.insert("2") print(bst.contains(6)) print(bst.contains(56)) From 47983041769633c60cdcdffb175b968790bb68de Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Tue, 22 Sep 2020 14:45:43 -0600 Subject: [PATCH 16/19] fixed for_each method --- binary_search_tree/binary_search_tree.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/binary_search_tree/binary_search_tree.py b/binary_search_tree/binary_search_tree.py index 81884a979d..e569d6694f 100644 --- a/binary_search_tree/binary_search_tree.py +++ b/binary_search_tree/binary_search_tree.py @@ -113,7 +113,7 @@ def for_each(self, fn): # call the function on the Left value self.left.for_each(fn) # if there is a node to the Right - else: + if self.right: # call the function on the Right value self.right.for_each(fn) From ab6bcd67b8ecd5596167d4154db6eecfb816456f Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Tue, 22 Sep 2020 20:05:54 -0600 Subject: [PATCH 17/19] completed in_order_print --- binary_search_tree/binary_search_tree.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/binary_search_tree/binary_search_tree.py b/binary_search_tree/binary_search_tree.py index e569d6694f..27a19406d7 100644 --- a/binary_search_tree/binary_search_tree.py +++ b/binary_search_tree/binary_search_tree.py @@ -123,7 +123,11 @@ def for_each(self, fn): # Print all the values in order from low to high # Hint: Use a recursive, depth first traversal def in_order_print(self): - pass + 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 @@ -157,12 +161,8 @@ def post_order_dft(self): bst.insert(6) bst.insert(3) bst.insert(4) -bst.insert("2") - -print(bst.contains(6)) -print(bst.contains(56)) -print(bst.get_max()) +bst.in_order_print() # bst.bft_print() # bst.dft_print() From 40d8fb63cd6d39d74701c603200fcd759e3ac7c6 Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Wed, 23 Sep 2020 19:17:17 -0600 Subject: [PATCH 18/19] Added preorder and postorder traversals --- binary_search_tree/binary_search_tree.py | 35 ++++++++++++++---------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/binary_search_tree/binary_search_tree.py b/binary_search_tree/binary_search_tree.py index 27a19406d7..419344cc42 100644 --- a/binary_search_tree/binary_search_tree.py +++ b/binary_search_tree/binary_search_tree.py @@ -113,7 +113,7 @@ def for_each(self, fn): # call the function on the Left value self.left.for_each(fn) # if there is a node to the Right - if self.right: + else: # call the function on the Right value self.right.for_each(fn) @@ -144,11 +144,20 @@ def dft_print(self): # Print Pre-order recursive DFT def pre_order_dft(self): - pass + 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): - pass + 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 @@ -162,15 +171,13 @@ def post_order_dft(self): bst.insert(3) bst.insert(4) -bst.in_order_print() - -# bst.bft_print() -# bst.dft_print() +bst.bft_print() +bst.dft_print() -# print("elegant methods") -# print("pre order") -# bst.pre_order_dft() -# print("in order") -# bst.in_order_dft() -# print("post order") -# bst.post_order_dft() +print("elegant methods") +print("pre order") +bst.pre_order_dft() +print("in order") +bst.in_order_print() +print("post order") +bst.post_order_dft() From 48bc51d56ef04421af379df20a9892a5ed38b61a Mon Sep 17 00:00:00 2001 From: Matt Martindale Date: Wed, 23 Sep 2020 21:41:00 -0600 Subject: [PATCH 19/19] MVP with Stretch Goals --- binary_search_tree/binary_search_tree.py | 44 +++++++++++++++++++++--- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/binary_search_tree/binary_search_tree.py b/binary_search_tree/binary_search_tree.py index 419344cc42..af2717c1da 100644 --- a/binary_search_tree/binary_search_tree.py +++ b/binary_search_tree/binary_search_tree.py @@ -97,12 +97,18 @@ def get_max(self): # ** ITERATIVE approach ** # initialize the max value //self's value + max_value = self.value # get a ref to the current node + current_node = self # Loop while there is still a Node + while current_node: # if the current value is greater than the max value, update the max value + if current_node.value > max_value: + max_value = current_node.value # move onto the next right node - + current_node = self.right # return max value + return max_value # Call the function `fn` on the value of each node def for_each(self, fn): @@ -113,7 +119,7 @@ def for_each(self, fn): # call the function on the Left value self.left.for_each(fn) # if there is a node to the Right - else: + if self.right: # call the function on the Right value self.right.for_each(fn) @@ -132,12 +138,40 @@ 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): - pass + # uses Queues + # set current_node + current_node = self + # create queue and initialize with current_node + queue = [current_node] + + # while there's data in the queue + while queue: + # dequeue from queue to the current_node + current_node = queue.pop(0) + print(current_node.value) + if current_node.left: + queue.append(current_node.left) + if current_node.right: + queue.append(current_node.right) # Print the value of every node, starting with the given node, # in an iterative depth first traversal def dft_print(self): - pass + # uses Stacks + # set current_node + current_node = self + # create queue and initialize with current_node + stack = [current_node] + + # while there's data in the queue + while stack: + # pop from stack to the current_node + current_node = stack.pop() + print(current_node.value) + if current_node.left: + stack.append(current_node.left) + if current_node.right: + stack.append(current_node.right) # Stretch Goals ------------------------- # Note: Research may be required @@ -171,7 +205,9 @@ def post_order_dft(self): bst.insert(3) bst.insert(4) +print("Breadth-first Traversal") bst.bft_print() +print("Depth-first Traversal") bst.dft_print() print("elegant methods")