Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 146 additions & 12 deletions binary_search_tree/binary_search_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,69 +17,203 @@ def __init__(self, value):

# Insert the given value into the tree
def insert(self, value):
pass
# 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
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
# 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
# otherwise recursively call insert on right node
else:
self.right.insert(value)


# Return True if the tree contains the value
# False if it does not
def contains(self, target):
pass
# if the value of the current node matches the target
if target == self.value:
# return True
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
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
if not self.right:
# return False
return False
# otherwise
else:
# return a call of 'contains' on the Right child passing in the target value
return 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):
pass
# check for an empty Tree
if not self.value:
# 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
return self.value
# otherwise return a call to get_max on the Right child
else:
return self.right.get_max()

# ** 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):
pass
# 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
if self.right:
# call the function on the Right value
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 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
# 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

# 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
"""
bst = BSTNode(1)
bst = BSTNode(4)

bst.insert(8)
bst.insert(5)
bst.insert(7)
bst.insert(6)
bst.insert(3)
bst.insert(4)
bst.insert(2)

print("Breadth-first Traversal")
bst.bft_print()
print("Depth-first Traversal")
bst.dft_print()

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()
125 changes: 116 additions & 9 deletions doubly_linked_list/doubly_linked_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 self.next:
return self.next
else:
return None

def prev_node(self):
if self.prev:
return self.prev
else:
return None

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
Expand All @@ -27,56 +51,139 @@ def __len__(self):
the old head node's previous pointer accordingly.
"""
def add_to_head(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.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
current head's next node the new head of the List.
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 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
self.head = new_head
return removed_head

"""
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):
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
current tail's previous node the new tail of the List.
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.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):
pass
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):
pass
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):
pass
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:
print(f"{current_node.value.value}")
current_node = current_node.next_node()
print(self.tail.get_value().value)

"""
Finds and returns the maximum value of all the nodes
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
Loading