Initial solution to homework

This commit is contained in:
Danila Fedorin 2019-09-26 23:30:53 -07:00
parent 677d9c277b
commit 5c43ffb602
3 changed files with 103 additions and 0 deletions

15
qselect.py Normal file
View File

@ -0,0 +1,15 @@
import random
def qselect(i, xs):
if xs == []: return None
pivot = xs.pop(random.randrange(len(xs)))
left = [x for x in xs if x < pivot]
right = [x for x in xs if x >= pivot]
if i > len(left):
return qselect(i - len(left) - 1, right)
elif i == len(left):
return pivot
else:
return qselect(i, left)

29
qsort.py Normal file
View File

@ -0,0 +1,29 @@
def qsort(xs):
if xs == []: return []
pivot = xs[0]
left = [x for x in xs if x < pivot]
right = [x for x in xs[1:] if x >= pivot]
return [qsort(left)] + [pivot] + [qsort(right)]
def sorted(tree):
if tree == []: return []
return sorted(tree[0]) + [tree[1]] + sorted(tree[2])
def search(tree, x):
return _sorted(tree, x) != []
def insert(tree, x):
node = _sorted(tree, x)
if node == []:
node.append([])
node.append(x)
node.append([])
def _sorted(tree, i):
if tree == []: return tree
pivot = tree[1]
if pivot == i: return tree
elif i < pivot: return _sorted(tree[0], i)
else: return _sorted(tree[2], i)

59
report.txt Normal file
View File

@ -0,0 +1,59 @@
Q: What's the best-case, worst-case, and average-case time complexities of quicksort.
Briefly explain each case.
A: Quicksort has the worst-case complexity of O(n^2). This is because in the worst case,
it will have to iterate over n, n-1, n-2,...,1 items. If the pivot is not picked
randomly, this is guranteed to occur when the list is sorted in either direction.
If the pivot is picked randomly, there is still a chance that the pivot will be either the largest or the smallest of the subarray in question.
The best-case complexity is O(n*log(n)) because each recursive operation will cut the size
of the input in half. Since the total number of items sorted at a particular depth is
always n, and the depth is logarithmically related to the number of items, the complexity
is O(n*logn(n)).
On average, Quicksort is also O(n*log(n)). It's quite difficult to consistently pick
a pivot that is either the smallest or the largest. I am unfamilliar with proof
techniques that help formalize this.
Q: What's the best-case, worst-case, and average-case time complexities? Briefly explain.
A: For the same reason as quicksort, in the worst case, the complexity is O(n^2).
If the algorithm consistently places all the elements to one side of the pivot,
it will need to continue sorting n, n-1, n-2, ..., 1 items.
In the best case, the input size is halved. This means that first n numbers
are processed, then n/2, then n/4, and so on. We can write this as n*(1+1/2+1/4+...).
The formula for the sum of a finite number of terms from a geometric series
is n(1-r^k)/(1-r). This simplifies to 2n(1-r^k). Since 1-2^k < 1,
n*(1+1/2+1/4+...) < 2n. This means the complexity is O(n).
For similarly hand-wavey reasons to those in Q0, the average case complexity aligns
with the best-case complexity rather than worst-case complexity.
Q: What are the time complexities for the operations implemented?
A: The complexity of sorted is O(n*log(n)) in best, and O(n^2) in worst case.
This is because of the way in which it implements
"flattening" the binary search tree - it recursively calls itself, creating
a new array from the results of the two recursive calls and the "pivot" between them.
Since creating a new array from arrays of length m and n is an O(m+n) operation.
Just like with qsort, in the best case, the tree is balanced with a depth of log(n).
Since concatenation at each level will effectively take n steps, the best case complexity
is O(n*log(n)). On the other hand, in the case of a tree with only right children,
the concatenation will take 1+2+...+n steps, which is in the order O(n^2).
Since insert and search both use _search, and perform no steps above O(1), they are
of the same complexity as _search. _search itself is O(logn) in the average case,
and O(n) in the worst case, so the same is true for the other algorithms. These
complexities are as such because _search is a simple binary search.
Debriefing:
1. Approximately how many hours did you spend on this assignment?
~1 hour.
2. Would you rate it as easy, moderate, or difficult?
Very easy, especially since it followed from the slides on day 1.
3. Did you work on it mostly alone, or mostly with other people?
Just me, myself, and I.
4. How deeply do you feel you understand the material it covers (0%100%)?
80%. Determining actual complexities of recursive functions has not yet been
taught in class, and I haven't consulted the books. For best and worst case,
though, It's pretty simple.
5. Any other comments?
I'd prefer the code for "broken qsort" to be available on Canvas. Maybe I missed it :)