Sort algorithms
Sort makes searches faster. Let’s cover famous sorting algorithms with their complexity and implementation. Implementation can vary a little, but the complexity in big O won’t vary.
Evaluation of sort algorithms
- Number of comparison
- Number of moves
Selection sort
Scan the unsorted numbers in an array to find the minimum number, then exchange this element with the first element of the unsorted numbers. Iterate this process until all elements are sorted.
def selection_sort(arr):
compare=0
move=0
for i in range(len(arr)-1):
idx=i
for j in range(i+1,len(arr)):
# search for the minimum
compare+=1
if arr[j] < arr[idx]:
idx=j
temp = arr[i]
arr[i] = arr[idx]
arr[idx] = temp
move+=3
return arr, compare, move
print(selection_sort([1,2,3,4,5]))
print(selection_sort([2,5,8,3,6,4,1,7]))
print(selection_sort([10,9,8,7,6,5,4,3,2,1]))
Output:
([1, 2, 3, 4, 5], 10, 12)
([1, 2, 3, 4, 5, 6, 7, 8], 28, 21)
([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 45, 27)
- Time complexity: O(n^2)
- Number of comparison: (n-1)+(n-2)+…+1 = n(n-1)/2
- Number of moves: 3(n-1)
Bubble sort
Compare two adjacent elements then sort these two. Iterate this process side by side until the end of the array, then iterate again from the beginning until all elements are sorted.
def bubble_sort(arr):
comp=0
move=0
for i in range(len(arr)-1):
for j in range(0,len(arr)-1-i):
# compare with the +1 index array
comp+=1
if arr[j] > arr[j+1]:
temp = arr[j]
arr[j] = arr[j+1]
arr[j+1] = temp
move+=3
return arr, comp, move
print(bubble_sort([1,2,3,4,5]))
print(bubble_sort([2,5,8,3,6,4,1,7]))
print(bubble_sort([10,9,8,7,6,5,4,3,2,1]))
Output:
([1, 2, 3, 4, 5], 10, 0)
([1, 2, 3, 4, 5, 6, 7, 8], 28, 39)
([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 45, 135)
- Time complexity: O(n^2)
- Number of comparison: (n-1)+(n-2)+…+1 = n(n-1)/2
- Number of moves
- Best case: 0, when already sorted
- Worst case: 3n(n-1)/2, when sorted in descending order
Insertion sort
Compare the i-th element with the sorted (i-1) to 0th elements, until finding a smaller element than i-th. Then put the i-th element behind that element.
def insertion_sort(arr):
compare0=0
compare1=0
move0=0
move1=0
move2=0
for i in range(1, len(arr)):
temp = arr[i]
move0+=1
j=i-1
compare0+=2
while((arr[j]>temp) and (j>=0)):
compare1+=2
arr[j+1] = arr[j]
move1+=1
j-=1
arr[j+1] = temp
move2+=1
return arr, compare0, compare1, move0, move1, move2, compare0+compare1, move0+move1+move2
print(insertion_sort([1,2,3,4,5]))
print(insertion_sort([2,5,8,3,6,4,1,7]))
print(insertion_sort([10,9,8,7,6,5,4,3,2,1]))
Output:
([1, 2, 3, 4, 5], 8, 0, 4, 0, 4, 8, 8)
([1, 2, 3, 4, 5, 6, 7, 8], 14, 26, 7, 13, 7, 40, 27)
([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 18, 90, 9, 45, 9, 108, 63)
- Time complexity: O(n^2)
- Number of comparison
- Best case: 2(n-1), when already sorted
- Worst case: 2(n-1)+n(n-1), when sorted in descending order
- Number of moves
- Best case: 2(n-1), when already sorted
- Worst case: 2(n-1)+n(n-1)/2, when sorted in descending order
- Number of comparison
Note that the time complexity becomes O(n) when inserting a new element to a sorted array.
Quick sort
Set the most left element as the pivot, put the rest of the smaller (larger) elements on its left (right), then iterate this process for the two segments, one on the left of the pivot and the other on the right of the pivot.
def partition(arr, left, right):
pivot = arr[left]
low = left+1
high = right
while(low<=high):
try:
while((pivot > arr[low])&(low<=right)):
low+=1
except:
pass
try:
while((pivot < arr[high])&(high>=(left+1))):
high-=1
except:
pass
if low<=high:
temp=arr[low]
arr[low]=arr[high]
arr[high]=temp
# now low>high
temp=arr[left]
arr[left]=arr[high]
arr[high]=temp
return high
def quick_sort(arr, left, right):
if left<=right:
pivot = partition(arr, left, right)
quick_sort(arr, left, pivot-1)
quick_sort(arr,pivot+1, right)
return arr
print(quick_sort([1,2,3,4,5],0,4))
print(quick_sort([2,5,8,3,6,4,1,7],0,7))
print(quick_sort([10,9,8,7,6,5,4,3,2,1],0,9))
Output:
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
- Time complexity
- Number of comparison
- Best case: O(nlog2(n)), when a pivot split the list to equal sizes each time
- Worst case: O(n^2), when a pivot split the list very imbalanced (e.g. already sorted array)
- Number of moves: smaller than the number of comparison
- Number of comparison
Leave a comment