Skip to content

Commit 2546431

Browse files
authored
Merge pull request #1 from ethyl2/Heather-Nuffer
Heather nuffer
2 parents 045b6d7 + 2ec6fcc commit 2546431

File tree

12 files changed

+657
-70
lines changed

12 files changed

+657
-70
lines changed

Pipfile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[[source]]
2+
name = "pypi"
3+
url = "https://pypi.org/simple"
4+
verify_ssl = true
5+
6+
[dev-packages]
7+
8+
[packages]
9+
10+
[requires]
11+
python_version = "3.8"

Pipfile.lock

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,22 @@ Implement this behavior in the RingBuffer class. RingBuffer has two methods, `ap
3434

3535
_You may not use a Python List in your implementation of the `append` method (except for the stretch goal)_
3636

37-
*Stretch Goal*: Another method of implementing a ring buffer uses an array (Python List) instead of a linked list. What are the advantages and disadvantages of using this method? What disadvantage normally found in arrays is overcome with this arrangement?
37+
_Stretch Goal_: Another method of implementing a ring buffer uses an array (Python List) instead of a linked list. What are the advantages and disadvantages of using this method? What disadvantage normally found in arrays is overcome with this arrangement?
38+
39+
Using an array was much easier for me to visualize and implement, because I didn't have to deal with setting the head and tail. Initializing the array to have the number of elements equal to the capacity made it easy to keep track of the current index and swap values.
40+
41+
Normally, adding to an array could cause more memory to have to be allocated if more memory is needed than what was initially allocated, but in this case, the capacity is fixed, so more memory won't be needed, so that is an advantage of this arrangement.
42+
43+
As far as big O goes, linked lists and arrays have similar values for several methods. However, finding an element in a linked list has O(n) versus an array's O(1), so that is one advantage of an array implementation.
44+
45+
| method | Array | DLL |
46+
| --------- | :----------: | ------------: |
47+
| append | 1 | 1 |
48+
| print nth | 1 | n |
49+
| add front | n | 1 |
50+
| del front | n | 1 |
51+
| del mid | n | 1 (n to find) |
52+
| find | n (or log n) | n |
3853

3954
For example:
4055

@@ -62,44 +77,46 @@ buffer.get() # should return ['d', 'e', 'f']
6277

6378
#### Task 2. Runtime Optimization
6479

65-
***!Important!*** If you are running this using PowerShell by clicking on the green play button, you will get an error that `names1.txt` is not found. To resolve this, run it, get the error, then `cd` into the `names` directory in the `python` terminal that opens in VSCode.
80+
**_!Important!_** If you are running this using PowerShell by clicking on the green play button, you will get an error that `names1.txt` is not found. To resolve this, run it, get the error, then `cd` into the `names` directory in the `python` terminal that opens in VSCode.
6681

6782
Navigate into the `names` directory. Here you will find two text files containing 10,000 names each, along with a program `names.py` that compares the two files and prints out duplicate name entries. Try running the code with `python3 names.py`. Be patient because it might take a while: approximately six seconds on my laptop. What is the runtime complexity of this code?
6883

6984
Six seconds is an eternity so you've been tasked with speeding up the code. Can you get the runtime to under a second? Under one hundredth of a second?
7085

71-
*You may not use the built in Python list, set, or dictionary in your solution for this problem. However, you can and should use the provided `duplicates` list to return your solution.*
86+
_You may not use the built in Python list, set, or dictionary in your solution for this problem. However, you can and should use the provided `duplicates` list to return your solution._
7287

7388
(Hint: You might try importing a data structure you built during the week)
7489

75-
7690
#### Task 3. Reverse a Linked List Recursively
7791

78-
Inside of the `reverse` directory, you'll find a basic implementation of a Singly Linked List. _Without_ making it a Doubly Linked List (adding a tail attribute), complete the `reverse_list()` function within `reverse/reverse.py` reverse the contents of the list using recursion, *not a loop.*
92+
Inside of the `reverse` directory, you'll find a basic implementation of a Singly Linked List. _Without_ making it a Doubly Linked List (adding a tail attribute), complete the `reverse_list()` function within `reverse/reverse.py` reverse the contents of the list using recursion, _not a loop._
7993

8094
For example,
95+
8196
```
8297
1->2->3->None
8398
```
99+
84100
would become...
101+
85102
```
86103
3->2->1->None
87104
```
88105

89-
While credit will be given for a functional solution, only optimal solutions will earn a ***3*** on this task.
106+
While credit will be given for a functional solution, only optimal solutions will earn a **_3_** on this task.
90107

91-
#### Stretch
92-
93-
* Say your code from `names.py` is to run on an embedded computer with very limited RAM. Because of this, memory is extremely constrained and you are only allowed to store names in arrays (i.e. Python lists). How would you go about optimizing the code under these conditions? Try it out and compare your solution to the original runtime. (If this solution is less efficient than your original solution, include both and label the strech solution with a comment)
108+
#### Stretch
94109

110+
- Say your code from `names.py` is to run on an embedded computer with very limited RAM. Because of this, memory is extremely constrained and you are only allowed to store names in arrays (i.e. Python lists). How would you go about optimizing the code under these conditions? Try it out and compare your solution to the original runtime. (If this solution is less efficient than your original solution, include both and label the strech solution with a comment)
95111

96112
### Rubric
97-
| OBJECTIVE | TASK | 1 - DOES NOT MEET Expectations | 2 - MEETS Expectations | 3 - EXCEEDS Expectations | SCORE |
98-
| ---------- | ----- | ------- | ------- | ------- | -- |
99-
| _Student should be able to construct a queue and stack and justify the decision to use a linked list instead of an array._ | Task 1. Implement a Ring Buffer Data Structure | Solution in `ring_buffer.py` DOES NOT run OR it runs but has multiple logical errors, failing 3 or more tests | Solution in `ring_buffer.py` runs, but may have one or two logical errors; passes at least 9/11 tests (Note that each _assert_ function is a test.) | Solution in `ring_buffer.py` has no syntax or logical errors and passes 11/11 tests (Note that each _assert_ function is a test.)| |
100-
| _Student should be able to construct a binary search tree class that can perform basic operations with O(log n) runtime._ | Task 2. Runtime Optimization | Student does NOT correctly identify the runtime of the starter code in `name.py` and optimize it to run in under 6 seconds | Student does not identify the runtime of the starter code in `name.py`, but optimizes it to run in under 6 seconds, with a solution of O(n log n) or better | Student does BOTH correctly identify the runtime of the starter code in `name.py` and optimizes it to run in under 6 seconds, with a solution of 0(n log n) or better | |
101-
| _Student should be able to construct a linked list and compare the runtime of operations to an array to make the optimal choice between them._ | Task 3. Reverse the contents of a Singly Linked List using Recursion| Student's solution in `reverse.py` is failing one or more tests | Student's solution in `reverse.py` is able to correctly print out the contents of the Linked List in reverse order, passing all tests, BUT, the runtime of their solution is not optimal (requires looping through the list more than once) | Student's solution in `reverse.py` is able to correctly print out the contents of the Linked List in reverse order, passing all tests AND it has a runtime of O(n) or better | |
102113

114+
| OBJECTIVE | TASK | 1 - DOES NOT MEET Expectations | 2 - MEETS Expectations | 3 - EXCEEDS Expectations | SCORE |
115+
| ---------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- |
116+
| _Student should be able to construct a queue and stack and justify the decision to use a linked list instead of an array._ | Task 1. Implement a Ring Buffer Data Structure | Solution in `ring_buffer.py` DOES NOT run OR it runs but has multiple logical errors, failing 3 or more tests | Solution in `ring_buffer.py` runs, but may have one or two logical errors; passes at least 9/11 tests (Note that each _assert_ function is a test.) | Solution in `ring_buffer.py` has no syntax or logical errors and passes 11/11 tests (Note that each _assert_ function is a test.) | |
117+
| _Student should be able to construct a binary search tree class that can perform basic operations with O(log n) runtime._ | Task 2. Runtime Optimization | Student does NOT correctly identify the runtime of the starter code in `name.py` and optimize it to run in under 6 seconds | Student does not identify the runtime of the starter code in `name.py`, but optimizes it to run in under 6 seconds, with a solution of O(n log n) or better | Student does BOTH correctly identify the runtime of the starter code in `name.py` and optimizes it to run in under 6 seconds, with a solution of 0(n log n) or better | |
118+
| _Student should be able to construct a linked list and compare the runtime of operations to an array to make the optimal choice between them._ | Task 3. Reverse the contents of a Singly Linked List using Recursion | Student's solution in `reverse.py` is failing one or more tests | Student's solution in `reverse.py` is able to correctly print out the contents of the Linked List in reverse order, passing all tests, BUT, the runtime of their solution is not optimal (requires looping through the list more than once) | Student's solution in `reverse.py` is able to correctly print out the contents of the Linked List in reverse order, passing all tests AND it has a runtime of O(n) or better | |
103119

104120
#### Passing the Sprint
121+
105122
Score ranges for a 1, 2, and 3 are shown in the rubric above. For a student to have _passed_ a sprint challenge, they need to earn an **average of at least 2** for all items on the rubric.

names/binary_search_tree.py

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
from dll_stack import Stack
2+
from dll_queue import Queue
3+
from collections import deque
4+
5+
'''
6+
import sys
7+
sys.path.append('../queue_and_stack')
8+
'''
9+
10+
11+
class BinarySearchTree:
12+
def __init__(self, value):
13+
self.value = value
14+
self.left = None
15+
self.right = None
16+
17+
# Insert the given value into the tree
18+
def insert(self, value):
19+
while self:
20+
# print("self: " + str(self))
21+
# print("value: " + str(value))
22+
if value < self.value:
23+
if not self.left:
24+
self.left = BinarySearchTree(value)
25+
return
26+
else:
27+
self = self.left
28+
else:
29+
if not self.right:
30+
self.right = BinarySearchTree(value)
31+
return
32+
else:
33+
self = self.right
34+
35+
def recursive_insert(self, value):
36+
if value < self.value:
37+
if self.left:
38+
self.left.insert(value)
39+
else:
40+
self.left = BinarySearchTree(value)
41+
else:
42+
if self.right:
43+
self.right.insert(value)
44+
else:
45+
self.right = BinarySearchTree(value)
46+
47+
def contains(self, target):
48+
# Return True if the tree contains the value
49+
# False if it does not
50+
while self:
51+
# print(self.value)
52+
# print(target)
53+
if target == self.value:
54+
return True
55+
elif target < self.value:
56+
if not self.left:
57+
return False
58+
else:
59+
self = self.left
60+
else:
61+
if not self.right:
62+
return False
63+
else:
64+
self = self.right
65+
66+
# Return the maximum value found in the tree
67+
68+
def get_max(self):
69+
# Initially set the max value to be self.
70+
max = self.value
71+
while self.right:
72+
if self.right.value > max:
73+
max = self.right.value
74+
self = self.right
75+
return max
76+
77+
# Call the function `cb` on the value of each node
78+
# You may use a recursive or iterative approach
79+
def for_each(self, cb):
80+
cb(self.value)
81+
if self.left and self.right:
82+
self.left.for_each(cb)
83+
self.right.for_each(cb)
84+
elif self.left:
85+
self.left.for_each(cb)
86+
elif self.right:
87+
self.right.for_each(cb)
88+
89+
def for_each_lecture(self, cb):
90+
cb(self.value)
91+
# base case is when self has no left or right
92+
if self.left:
93+
self.left.for_each(cb)
94+
if self.right:
95+
self.right.for_each(cb)
96+
97+
def for_each_iterative_depth_first(self, cb):
98+
stack = []
99+
stack.append(self)
100+
while len(stack) > 0:
101+
current_node = stack.pop()
102+
# Checking the right first will result in the same order as the
103+
# recursive (lecture) version above
104+
if current_node.right:
105+
stack.append(current_node.right)
106+
if current_node.left:
107+
stack.append(current_node.left)
108+
cb(current_node.value)
109+
110+
def for_each_iterative_breadth_first(self, cb):
111+
q = deque()
112+
q.append(self)
113+
while len(q) > 0:
114+
current_node = q.popleft()
115+
# for left to right ordering, check left first.
116+
if current_node.left:
117+
q.append(current_node.left)
118+
if current_node.right:
119+
q.append(current_node.right)
120+
cb(current_node.value)
121+
122+
# DAY 2 Project -----------------------
123+
124+
# Print all the values in order from low to high
125+
# Hint: Use a recursive, depth first traversal
126+
# AKA Inorder Traversal
127+
# Recursively:
128+
# 1. Visit left subtree
129+
# 2. Visit node
130+
# 3. Visit right subtree
131+
132+
def in_order_print(self, node):
133+
if node == None:
134+
return
135+
self.in_order_print(node.left)
136+
print(node.value)
137+
self.in_order_print(node.right)
138+
139+
# Print the value of every node, starting with the given node,
140+
# in an iterative breadth first traversal
141+
142+
def bft_print(self, node):
143+
q = Queue()
144+
while node is not None:
145+
print(node.value)
146+
# Stick all of the node's children in the end of the queue.
147+
if node.left:
148+
q.enqueue(node.left)
149+
if node.right:
150+
q.enqueue(node.right)
151+
if q.len() > 0:
152+
# Get the first node in the queue and continue the loop with it.
153+
node = q.dequeue()
154+
else:
155+
break
156+
return
157+
158+
# Print the value of every node, starting with the given node,
159+
# in an iterative depth first traversal
160+
161+
def dft_print(self, node):
162+
s = Stack()
163+
while node is not None:
164+
print(node.value)
165+
# Stick all of the node's children in the end of the stack.
166+
if node.left:
167+
s.push(node.left)
168+
if node.right:
169+
s.push(node.right)
170+
if s.len() > 0:
171+
# Get the last node in the stack and continue the loop with it.
172+
node = s.pop()
173+
else:
174+
break
175+
return
176+
177+
# STRETCH Goals -------------------------
178+
# Note: Research may be required
179+
180+
# Print Pre-order recursive DFT
181+
'''
182+
To traverse a binary tree in preorder,
183+
1. Visit the root.
184+
2. Traverse the left sub tree of root.
185+
3. Traverse the right sub tree of root.
186+
'''
187+
188+
def pre_order_dft(self, node):
189+
if node == None:
190+
return
191+
print(node.value)
192+
self.pre_order_dft(node.left)
193+
self.pre_order_dft(node.right)
194+
195+
'''
196+
To traverse a binary tree in postorder traversal,
197+
1. Traverse the left sub tree of root.
198+
2. Traverse the right sub tree of root.
199+
3. Visit the root.
200+
'''
201+
# Print Post-order recursive DFT
202+
203+
def post_order_dft(self, node):
204+
if node == None:
205+
return
206+
207+
self.post_order_dft(node.left)
208+
self.post_order_dft(node.right)
209+
print(node.value)
210+
211+
212+
'''
213+
my_bst = BinarySearchTree(1)
214+
my_bst.insert(8)
215+
my_bst.insert(5)
216+
my_bst.insert(7)
217+
my_bst.insert(6)
218+
my_bst.insert(3)
219+
my_bst.insert(4)
220+
my_bst.insert(2)
221+
# my_bst.bft_print(my_bst)
222+
# my_bst.dft_print(my_bst)
223+
# my_bst.pre_order_dft(my_bst)
224+
my_bst.post_order_dft(my_bst)
225+
'''

names/dll_queue.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
2+
# import sys
3+
# sys.path.append('../doubly_linked_list')
4+
from doubly_linked_list import DoublyLinkedList
5+
6+
# FIFO (first in, first out)
7+
8+
9+
class Queue:
10+
def __init__(self):
11+
self.size = 0
12+
# Why is our DLL a good choice to store our elements?
13+
# Pretty straight-forward to add to head & tail, and remove from head & tail.
14+
# Doesn't need an up-front allocation of memory.
15+
# O(1) for both sides for a DLL.
16+
# self.storage = ?
17+
self.storage = DoublyLinkedList()
18+
19+
def enqueue(self, value):
20+
# Add to tail
21+
self.storage.add_to_tail(value)
22+
self.size += 1
23+
24+
def dequeue(self):
25+
# Remove head
26+
value = self.storage.remove_from_head()
27+
if self.len() > 0:
28+
self.size -= 1
29+
return value
30+
31+
def len(self):
32+
return self.size

0 commit comments

Comments
 (0)