Skip to content

Batuhan balta #412

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
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
183 changes: 183 additions & 0 deletions names/binary_search_tree.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
"""
Binary search trees are a data structure that enforce an ordering over
the data they store. That ordering in turn makes it a lot more efficient
at searching for a particular piece of data in the tree.
This part of the project comprises two days:
1. Implement the methods `insert`, `contains`, `get_max`, and `for_each`
on the BSTNode class.
2. Implement the `in_order_print`, `bft_print`, and `dft_print` methods
on the BSTNode class.
"""
from queue import Queue
from stack import Stack


class BSTNode:
def __init__(self, value):
self.value = value
self.left = None
self.right = None

# Insert the given value into the tree
def insert(self, value):
# Case 1: value is less than self.value
if value < self.value:
# If there is no left child, insert value here
if self.left is None:
self.left = BSTNode(value)
# ELSE Repeat the process on left subtree
else:
self.left.insert(value)

# Case 2: value is greater than or equal self.value
elif value >= self.value:
if self.right is None:
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):
# Case 1: If self.value is equal to the target
if self.value == target:
return True

# Case 2: if target is less than self.value
if target < self.value:
# if self.left is None, it isn't in the tree
if self.left is None:
return False
else:
return self.left.contains(target)
# Case 3: otherwise
else:
if self.right is None:
return False
else:
return self.right.contains(target)

# Return the maximum value found in the tree
def get_max(self):
if self.right is not None:
return self.right.get_max()
else:
return self.value

# Call the function `fn` on the value of each node

def for_each(self, fn):
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, node):
# if the current node is None
# we know we've reached the end of a recursion
# (base case) we want to return
if self is None:
return

# check if we can "move left"
if self.left is not None:
self.left.in_order_print(self.left)

# visit the node by printing its value
print(self.value)

# check if we can "move right"
if self.right is not None:
self.right.in_order_print(self.right)

# Print the value of every node, starting with the given node,
# in an iterative breadth first traversal
def bft_print(self, node):

# You should import the queue class from earlier in the
# week and use that class to implement this method
# Use a queue to form a "line"
# for the nodes to "get in"

# start by placing the root in the queue

# need a while loop to iterate
# what are we checking in the while statement?
# while length of queue is greater than 0
# dequeue item from front of queue
# print that item

# place current item's left node in queue if not None
# place current item's right node in queue if not None

q = Queue()
q.enqueue(self)
while len(q) > 0:

dequeued = q.dequeue()
print(dequeued.value)

if dequeued.left is not None:
q.enqueue(dequeued.left)
if dequeued.right is not None:
q.enqueue(dequeued.right)

# Print the value of every node, starting with the given node,
# in an iterative depth first traversal

def dft_print(self, node):

# initialize an empty stack
# push the root node onto the stack

# need a while loop to manager our iteration
# if stack is not empty enter the while loop
# pop top item off the stack
# print that item's value

# if there is a right subtree
# push right item onto the stack

# if there is a left subtree
# push left item onto the stack
s = Stack()
s.push(self)

while len(s) > 0:

popped = s.pop()
print(popped.value)

if popped.right:
s.push(popped.right)

if popped.left:
s.push(popped.left)

# Stretch Goals -------------------------
# Note: Research may be required

# Print Pre-order recursive DFT

def pre_order_dft(self, node):
print(self.value)

if self.left:
self.left.pre_order_dft(self)
if self.right:
self.right.pre_order_dft(self)
# Print Post-order recursive DFT

def post_order_dft(self, node):
if self.left:
self.left.post_order_dft(self)
if self.right:
self.right.post_order_dft(self)

print(self.value)
27 changes: 21 additions & 6 deletions names/names.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import time
from binary_search_tree import BSTNode

start_time = time.time()

Expand All @@ -13,14 +14,28 @@
duplicates = [] # Return the list of duplicates in this data structure

# Replace the nested for loops below with your improvements
for name_1 in names_1:
for name_2 in names_2:
if name_1 == name_2:
duplicates.append(name_1)
# n log(n)
first_list = BSTNode(names_1[0])
next(iter(names_1))

for name in names_1:
first_list.insert(name)

for name in names_2:
if first_list.contains(name):
duplicates.append(name)

# n*n
# for name_1 in names_1:
# for name_2 in names_2:
# if name_1 == name_2:
# duplicates.append(name_1)

end_time = time.time()
print (f"{len(duplicates)} duplicates:\n\n{', '.join(duplicates)}\n\n")
print (f"runtime: {end_time - start_time} seconds")
print(f"{len(duplicates)} duplicates:\n\n{', '.join(duplicates)}\n\n")
print(f"runtime: {end_time - start_time} seconds")

# runtime: 0.056012630462646484 seconds

# ---------- Stretch Goal -----------
# Python has built-in tools that allow for a very efficient approach to this problem
Expand Down
21 changes: 21 additions & 0 deletions names/queue.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from singly_linked_list import Node, LinkedList


class Queue:
def __init__(self):
self.size = 0
self.storage = LinkedList()

def __len__(self):
return self.size

def enqueue(self, value):
self.size += 1
self.storage.add_to_tail(value)
return self.storage.tail.get_value()

def dequeue(self):
if self.size == 0:
return
self.size -= 1
return self.storage.remove_head()
122 changes: 122 additions & 0 deletions names/singly_linked_list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
class Node:
# Stores two pieces of data:
# 1. Value
# 2. The Next Node

# Methods
# 1. Get value
# 2. Set value
# 3. Get next
# 4. Set next
def __init__(self, value=None, next_node=None):
self.value = value
self.next_node = next_node

def get_value(self):
return self.value

def set_value(self, new_value):
self.value = new_value

def get_next(self):
return self.next_node

def set_next(self, new_next):
self.next_node = new_next


class LinkedList:
# 1. Ref to the head Node
# 2. Ref to the tail Node

def __init__(self):
self.head = None
self.tail = None

# Behavior
# 1. Append

def add_to_tail(self, value):
new_tail = Node(value)
if not self.head: # If no head
self.head = new_tail
else: # If there is head
self.tail.set_next(new_tail)
self.tail = new_tail

# 2. Prepend

def add_to_head(self, value):
new_head = Node(value) # Create the new head
new_head.set_next(self.head) # Old head becomes the next of new head
if self.head is None: # If there was no item in the list;
self.tail = new_head # Then head and tail becomes the same value
self.head = new_head # Set new head as head anyways

# 3. Remove Head

def remove_head(self):

if not self.head: # No item
return None

if not self.head.get_next(): # One Item
head = self.head
self.head = None
self.tail = None
return head.get_value()

value = self.head.get_value() # Multiple items
self.head = self.head.get_next()
return value

# 4. Remove Tail

def remove_tail(self):
if not self.head: # No item
return None

if self.head is self.tail: # One item
value = self.head.get_value()
self.head = None
self.tail = None
return value

current = self.head # Multiple items

while current.get_next() is not self.tail:
current = current.get_next()

value = self.tail.get_value()
self.tail = current
self.tail.set_next(None)
return value

# 5. Contains?

def contains(self, value):
if not self.head: # No item
return False

current = self.head # If there is at least one item

while current:
if current.get_value() == value:
return True
current = current.get_next()
return False

# 6. Get Maximum

def get_max(self):
if not self.head: # No item
return None

max_value = self.head.get_value()
current = self.head.get_next()

while current:
if current.get_value() > max_value:
max_value = current.get_value()
current = current.get_next()
return max_value
24 changes: 24 additions & 0 deletions names/stack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from singly_linked_list import LinkedList
import sys
sys.path.append('../singly_linked_list/')


class Stack:
def __init__(self):
self.size = 0
self.storage = LinkedList()

def __len__(self):
return self.size

def push(self, value):
value == self.storage.add_to_head(value)
self.size += 1
return value

def pop(self):
if self.size == 0:
return None
value = self.storage.remove_head()
self.size -= 1
return value
Loading