We learned some sorting methods this week,
especially quick sort and merge sort. At first, the algorithm for quick sort is
just set the first item in the list as the pivot and move everything smaller
than the pivot to the left of that pivot and move everything greater than the
pivot to the right side of the pivot like this:
smaller_than_pivot = [x for x in L[1:] if x
< pivot]
larger_than_pivot = [x for x in L[1:] if x
>= pivot]
Then use recursion
return quick(smaller_than_pivot) + [pivot]
+ quick(larger_than_pivot)
to make items on left and right side of the
pivot sorted. Then the function is done. However, we ran into a problem in a
special case. For example, when the list is already sorted, either greatest to
the smallest or smallest to the greatest, the number of recursion needed would
be the same as the size of inputs. So for a very large list, this algorithm
will exceed the recursion depth. The way to solve this problem is that we can
choose the pivot randomly. For instance, is not chosen randomly, list [1, 2, 3,
4, 5] will have 5 recursion, but by choosing a random pivot, we can easily avoid
this problem, since 3 could be chosen as a pivot at first.
For merge sort, we wrote a helper function
merge2,
def merge2(L1:list, L2:list) -> list:
"""return merge of L1 and L2
NOTE: modifies L1 and L2
>>> merge2([1, 3, 5], [2, 4, 6])
[1, 2, 3, 4, 5, 6]
>>> merge2([1, 2, 3], [0, 4, 5])
[0, 1, 2, 3, 4, 5]
>>> merge2([0], [1, 2, 3, 4])
[0, 1, 2, 3, 4]
"""
L
= []
L1.reverse()
L2.reverse()
while L1 and L2:
if L1[-1] < L2[-1]:
L.append(L1.pop())
else:
L.append(L2.pop())
L1.reverse()
L2.reverse()
return L + L1 + L2
This function merge two lists together in a
non-decreasing order. Then it's easier to write merge_sort function.
def merge_sort(L):
"""Produce copy of L in non-decreasing order
>>> merge_sort([1, 5, 3, 4, 2])
[1, 2, 3, 4, 5]
"""
if len(L) < 2 :
return L
else :
left_sublist = L[:len(L)//2]
right_sublist = L[len(L)//2:]
return merge2(merge_sort(left_sublist),
merge_sort(right_sublist))

