COL100-Lecture 14 Sorting
COL100-Lecture 14 Sorting
Ordered Lists
Given a set A, and a total ordering ≤ on A.
Properties
• [ ] is an ordered (or sorted) list
• Each singleton list [ a ] is a ordered (or sorted) list (for each a in A)
• If L is a sorted list, and x ≤ L[ i ] then x ≤ L[ j ] for all j ≥ i (0 ≤ i, j < len(L))
• If L is a sorted list, and x ≥ L[ i ] then x ≥ L[ j ] for all j ≤ i (0 ≤ i, j < len(L))
• If L1 and L2 are sorted lists of elements from A (ordered according to ≤ on A) such
that len(L1) = m, and if L1[ m-1 ] ≤ L2[ 0 ] then app(L1, L2) is a sorted list (ordered
according to ≤ on A)
• If L is a sorted list, element x in A such that for each j (0 ≤ i < len(L)): L[ j ] ≤ x, then
L.append(x) is sorted.
Exercise: Show that app(L1, L2) is sorted if L1[ m - 1] ≤ L2[ 0 ] where len(L1) = m
def insertionsort(L):
# INPUT L : any list (L s.t. True)
# OUTPUT L1 is a permutation of L, L1 is sorted
# Initialisation
n = len(L)
L1 = [ ]
# Maintain L1 as a sorted list
# Look at each element of L in turn (k in 0..n-1),
# insert L[k] into the right position in L1
# EXIT when k == n
# n iterations of outer for loop
return L1
Sorting by Insertion: program
def insertionsort_mistake(L):
# INPUT L : any list (L s.t. True)
# OUTPUT L1 is a permutation of L, L1 is sorted
# Initialisation
n = len(L)
L1 = [ ]
for k in range (0,n):
# INVARIANT: FORALL(0≤i<k): L1[i] == L[j] for some (0≤j<k)
# /\ FORALL(0≤i,j<k): L1[i] ≤ L1[j]
i = 0
while (i<k) & (L1[i] < L[k]): # FORALL(0≤j<i): L1[j]<L[k]
i += 1
# EXIT when L1[i] ≥ L[k]
# upto k iterations of inner while loop
L1.insert(i,L[k]) # Do not assume this is O(1)
# EXIT when k == n
# n iterations of outer for loop
return L1
Sorting by Insertion: correct program
def insertionsort(L):
# INPUT L : any list (L s.t. True)
# OUTPUT L is a permutation of Linit, L is sorted
# Initialisation
n = len(L)
L1 = [ ]
for k in range (0,n):
# INVARIANT: FORALL(0≤i<k): L1[i] == L[j] for some (0≤j<k)
# /\ FORALL(0≤i,j<k): L1[i] ≤ L1[j]
i = 0
posfound = False
while (i<k) & (not posfound): # FORALL(0≤j<i):L1[j]≤L[k]
if (L1[i] < L[k]):
i += 1
else:
posfound = True
# EXIT when L1[i] ≥ L[k] or i=k
# upto k iterations of inner while loop
L1.insert(i,L[k]) # What is the complexity?
# EXIT when k == n
# n iterations of outer for loop
return L1
Merging sorted lists: program
# Given two sorted lists L1 and L2, return a new sorted list L3
# that combine the elements of L1 and L2
# INPUT L1, L2 sorted lists
# OUTPUT L3 s.t L3 sorted list /\ L3 permutation of app(L1,L2)
def merge( L1, L2):
# Initialisation
L3 = [ ]
m = len(L1)
n = len(L2)
i = 0
j = 0
# INVARIANT for all k, h (0≤k,m≤i+j): k < m implies L3[k] ≤ L3[h]
# /\ for all k (i ≤k < m): L3[i+j] ≤ L1[k] /\
# /\ for all h (j ≤h < m): L3[i+j] ≤ L2[h]
while (i < m) & (j < n): # in each iteration either i or j increases by 1
if L1[i] <= L2[j]: # find the lower of L[i] and L[j] to copy over to L3
L3.append(L1[i])
i += 1
else:
L3.append(L2[j])
j+= 1
if (i == m):
while (j < n): # Copy remaining L2 elements
L3.append(L2[j])
j+= 1
else:
while (i < m): # Copy remaining L1 elements
L3.append(L1[i])
i += 1
return L3 # O(m+n)
Sorting by Merging
def mergesort(L):
# INPUT L : any list (L s.t. True)
# OUTPUT L3 is a permutation of L, L3 is sorted
n = len(L)
if (n <= 1 ): # L is already sorted
return L
else:
mid = n//2 # find mid point of list
# Divide the list in 2 roughly equal parts,
# Note: if we can’t do so, then not efficient
L1 = L[0:mid] # first “half”
L2 = L[mid:n] # second “half”
# recursively sort first half # T(n//2)
L1sort = mergesort(L1)
# recursively sort second half # T(n//2)
L2sort = mergesort(L2)
# merge sorted lists O(n//2 + n//2)
L3 = merge(L1sort, L2sort)
# T(n) = 2 T(n//2) + O(n)
return L3
Sorting by Partitioning