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
32 changes: 17 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,46 +58,48 @@ buffer.get() # should return ['d', 'e', 'f']

#### Task 2. Runtime Optimization

***!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.
**_!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.

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?

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?

*You may not use the built in Python list or set for this problem*
_You may not use the built in Python list or set for this problem_

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


#### Task 3. Reverse a Linked List

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.
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.

For example,

```
1->2->3->None
```

would become...

```
3->2->1->None
```

While credit will be given for a functional solution, only optimal solutions will earn a ***3*** on this task.

#### Stretch
While credit will be given for a functional solution, only optimal solutions will earn a **_3_** on this task.

* 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)
#### Stretch

- 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)

### Rubric
| OBJECTIVE | TASK | 1 - DOES NOT MEET Expectations | 2 - MEETS Expectations | 3 - EXCEEDS Expectations | SCORE |
| ---------- | ----- | ------- | ------- | ------- | -- |
| _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 7/9 tests | Solution in `ring_buffer.py` has no syntax or logical errors and passes 9/9 tests | |
| _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 correctly identifies the runtime of the starter code in `name.py` and 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 O(n) or better | |
| _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 | 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 | |
| _Student should be able to write code that utilizes Python Collections_ | [STRETCH] Optimize code from Task 2, given the constraint that **only standard Python collections** may be used to store names | Level 1 solution provided | Level 2 solution provided | Level 3 solution provided | |
| **FINAL SCORE** | _(3 tasks + 1 STRETCH goal)_ | **0-5** | **6-9** | **10-12** | |

| OBJECTIVE | TASK | 1 - DOES NOT MEET Expectations | 2 - MEETS Expectations | 3 - EXCEEDS Expectations | SCORE |
| ---------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- |
| _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 7/9 tests | Solution in `ring_buffer.py` has no syntax or logical errors and passes 9/9 tests | |
| _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 correctly identifies the runtime of the starter code in `name.py` and 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 O(n) or better | |
| _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 | 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 | |
| _Student should be able to write code that utilizes Python Collections_ | [STRETCH] Optimize code from Task 2, given the constraint that **only standard Python collections** may be used to store names | Level 1 solution provided | Level 2 solution provided | Level 3 solution provided | |
| **FINAL SCORE** | _(3 tasks + 1 STRETCH goal)_ | **0-5** | **6-9** | **10-12** | |

#### Passing the Sprint

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.
50 changes: 50 additions & 0 deletions names/binary_search_tree.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import sys


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

def insert(self, value):
if value < self.value:
if not self.left:
self.left = BinarySearchTree(value)
else:
self.left.insert(value)
else:
if not self.right:
self.right = BinarySearchTree(value)
else:
self.right.insert(value)


def contains(self, target):
if self.value == target:
return True

if target < self.value:
if not self.left:
return False
else:
return self.left.contains(target)
else:
if not self.right:
return False
else:
return self.right.contains(target)


def get_max(self):
if not self.right:
return self.value
else:
return self.right.get_max()

def for_each(self, cb):
if self.right:
self.right.for_each(cb)
if self.left:
self.left.for_each(cb)
cb(self.value)
17 changes: 12 additions & 5 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 BinarySearchTree

start_time = time.time()

Expand All @@ -11,12 +12,18 @@
f.close()

duplicates = []
for name_1 in names_1:
for name_2 in names_2:
if name_1 == name_2:
duplicates.append(name_1)
# for name_1 in names_1:
# for name_2 in names_2:
# if name_1 == name_2:
# duplicates.append(name_1)
names1search = BinarySearchTree(names_1[0])
for i in range(1, len(names_1)):
names1search.insert(names_1[i])

for i in names_2:
if names1search.contains(i):
duplicates.append(i)

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

16 changes: 12 additions & 4 deletions reverse/reverse.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ def add_to_head(self, value):
node = Node(value)
if self.head is not None:
node.set_next(self.head)

self.head = node

def contains(self, value):
if not self.head:
return False
# get a reference to the node we're currently at; update this as we traverse the list
current = self.head
# check to see if we're at a valid node
# check to see if we're at a valid node
while current:
# return True if the current value we're looking at matches our target value
if current.get_value() == value:
Expand All @@ -43,5 +43,13 @@ def contains(self, value):
return False

def reverse_list(self):
# TO BE COMPLETED
pass
if not self.head:
return False
previous = None
current = self.head
while current != None:
next = current.get_next()
current.set_next(previous)
previous = current
current = next
self.head = previous
8 changes: 4 additions & 4 deletions reverse/test_reverse.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def test_contains(self):
def test_empty_reverse(self):
self.list.reverse_list()
self.assertEqual(self.list.head, None)

def test_single_reverse(self):
self.list.add_to_head(1)
self.list.reverse_list()
Expand All @@ -39,9 +39,9 @@ def test_longer_reverse(self):
self.assertEqual(self.list.head.value, 1)
self.assertEqual(self.list.head.get_next().value, 2)
self.assertEqual(self.list.head.get_next().get_next().value, 3)






if __name__ == '__main__':
unittest.main()
unittest.main()
21 changes: 19 additions & 2 deletions ring_buffer/ring_buffer.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,24 @@ def __init__(self, capacity):
self.storage = [None]*capacity

def append(self, item):
pass

for i in range(0,len(self.storage)):
if self.storage[i] == None:
self.storage[i] = item
i = len(self.storage)
return
elif i == len(self.storage) - 1:
self.storage[self.current] = item
if self.current < len(self.storage):
self.current = self.current + 1
else:
self.current = 0
return


def get(self):
pass
result = []
for i in self.storage:
if i != None:
result.append(i)
return result
3 changes: 2 additions & 1 deletion ring_buffer/test_ring_buffer.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def test_ring_buffer(self):
self.buffer.append('c')
self.buffer.append('d')
self.assertEqual(len(self.buffer.storage), 5)

self.assertEqual(self.buffer.get(), ['a', 'b', 'c', 'd'])

self.buffer.append('e')
Expand All @@ -31,4 +32,4 @@ def test_ring_buffer(self):


if __name__ == '__main__':
unittest.main()
unittest.main()