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
305 changes: 290 additions & 15 deletions binary_search_tree/binary_search_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,218 @@
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', '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 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
Expand All @@ -17,53 +229,114 @@ def __init__(self, value):

# Insert the given value into the tree
def insert(self, value):
pass
#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:
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 the value of the current node matches the target
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
def bft_print(self, node):
queue = Queue()
queue.enqueue(node)
while queue.size > 0:
node = queue.dequeue()
print(node.value)
if node.left:
queue.enqueue(node.left)
if node.right:
queue.enqueue(node.right)

# Print the value of every node, starting with the given node,
# in an iterative depth first traversal
def dft_print(self):
pass
def dft_print(self, node):
stack = Stack()
stack.push(node)
while not stack.isEmpty():
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
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):
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)
Expand All @@ -73,13 +346,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()
Loading