Worst case is O(n^2)
Average case is O(nlogn)
Performance depends largely on Pivot selection
In [32]:
# source: https://github.com/joeyajames/Python/blob/master/SortingAlgorithms.py
def select_pivot(array, low=0, hi=None):
if not hi:
hi = len(array) - 1
mid = (low + hi) // 2
s = sorted([array[low], array[mid], array[hi]])
#choice the middle element in `s`
if s[1] == array[low]:
return low
if s[1] == array[mid]:
return mid
return hi
border
: any elements in left of border
are less than pivot
In [ ]:
In [36]:
def quick_sort(array, lo=0, hi=None):
if hi is None:
hi = len(array) - 1
def _quick_sort(array, lo, hi):
if lo >= hi:
return
pivot = partition(array, lo, hi)
_quick_sort(array, lo, pivot-1)
_quick_sort(array, pivot+1, hi)
return _quick_sort(array, lo, hi)
def partition(array, lo, hi):
# simply select first element as pivot
# or use sorted(low, midum, high)[1] as pivot,
# and exchange with a[lo]
pivot = array[lo]
border = lo # border: any elements in left of border are less than pivot
for i in range(lo, hi + 1):
if array[i] < pivot:
border +=1
array[i], array[border] = array[border], array[i]
array[lo], array[border] = array[border], array[lo] # exchange border with pivoit
return border
In [39]:
# from grokking algorithms page no.65
def quick_sort2(array):
if len(array) < 2:
return array
pivot = array[0]
less = [v for v in array[1:] if v <=pivot]
greater = [v for v in array[1:] if v > pivot]
return quick_sort2(less) + [pivot] + quick_sort2(greater)
In [40]:
alist = [54,26,93,17,77,31,20, 44,55,20]
blist = quick_sort2(alist)
print("before: ",alist)
print("after : ",blist)
In [41]:
def quick_sort_dual_pivot(a):
_quick_sort_dual_pivot(a, 0, len(a) - 1)
return a
def _quick_sort_dual_pivot(a, lo, hi):
if lo >= hi:
return
if a[lo] > a[hi]:
a[lo], a[hi] = a[hi], a[lo]
pivot1 = a[lo]
pivot2 = a[hi]
if (pivot1 == pivot2):
while pivot1 == pivot2 and lo < hi:
lo +=1
pivot1 = a[lo]
l = lo + 1
h = hi - 1
i = lo + 1
while i <= h:
if a[i] < pivot1:
a[i], a[l] = a[l], a[i]
i += 1
l += 1
elif a[i] > pivot2:
a[i], a[h] = a[h], a[i]
h -= 1
else:
i += 1
l -= 1
h += 1
a[lo], a[l] = a[l], a[lo]
a[hi], a[h] = a[h], a[hi]
_quick_sort_dual_pivot(a, lo, l-1)
_quick_sort_dual_pivot(a, l+1, h-1)
_quick_sort_dual_pivot(a, h+1, hi)
In [43]:
alist = [54,26,99,93,17,77,31,20, 44,55,20]
quick_sort_dual_pivot(alist)
print(alist)
In 3 Way QuickSort, an array arr[l..r] is divided in 3 parts:
a) arr[l..i] elements less than pivot.
b) arr[i+1..j-1] elements equal to pivot.
c) arr[j..r] elements greater than pivot.
In [44]:
def quick_sort_3way(a):
_quick_sort_3way(a, 0, len(a) - 1)
return a
def _quick_sort_3way(a, lo, hi):
if lo >= hi:
return
l = lo
h = hi
i = l + 1
pivot = a[lo]
while i <= h:
if a[i] < pivot:
a[i], a[l] = a[l], a[i]
i += 1
l += 1
elif a[i] > pivot:
a[i], a[h] = a[h], a[i]
h -= 1
else:
i += 1
_quick_sort_3way(a, lo, l-1)
_quick_sort_3way(a, h+1, hi)
In [ ]: