Common Sorting Algorithms
Sorting algorithms are a part of almost all introductory algorithm courses. Though sorting is a little more complex than what this post may convey, I thought it would be a good way to refresh my concepts on this topic.
Insertion Sort
Insertion Sort works well on smaller data or data that is partially sorted but performs terribly everywhere else on account of its $O(n^{2})$ worst-case time complexity. The algorithm is straight-forward.
InsertionSort(array, size)
for j:= 2 to size do
key := array[j]
i:= j - 1
while i > 0 and array[i] > key do
array[i + 1] := array[i]
i := i - 1
array[i + 1] := key
return array
Essentially what is happening is that whenever an element is considered, it is placed in its correct position without considering the elements after it.
The best-case time-complexity is $O(n)$, which happens when the input sequence is already sorted. The reason is evident when we consider that the while loop condition of $array[i] > key$ never holds, and therefore each element is considered only one.
It is an in-place and stable sorting technique.
MergeSort
MergeSort(array, size)
start := 0
end := size - 1
MergeSortRecursive(array, start, end)
Merge(array, start, mid, end)
size1 := mid - start + 1
size2 := end - mid
arrayleft = array[start ... mid]
arrayright = array[mid + 1 ... end]
i := 0
j := 0
for k := start to (end - 1) do
if (arrayleft[i] <= arrayright[j])
then do
array[k] = arrayleft[i]
i := i + 1
else
array[k] = arrayright[j]
j := j + 1
// It is very likely that one of i or j will reach size1 or size2
before the other. Once that condition is reached, all remaining elements
of `array` will be those of the unended subarray.
MergeSortRecursive(array, start, end)
if start < end then do
mid := floor((start + end) / 2)
MergeSortRecursive(array, start, mid)
MergeSortRecursive(array, mid + 1, end)
Merge(array, start, mid, end)
QuickSort
QuickSort is one of the best general sorting algorithms. It has a worst-case time complexity of $O(nlog(n))$.
It uses a partition based approach. Fundamentally, the collection of data is partitioned about a particular point, also called a pivot. There are several ways of arriving at this point, but for the purpose of this post, we will consider the last element as the pivot. Following that, this point will be inserted in a location which satisfies the invariant that any element to the left of the pivot are smaller than it and those after it are greater.
One that is done, a simple divide and conquer approach is used to sort the collection.
Quicksort can be implemented as shown below.
Partition (array, start, end)
x := array[end]
i := start - 1
for j := p to end - 1 do
if array[j] <= x
then do
i := i + 1
array[i] <--> array[j]
array[i + 1] <--> array[end]
return i + 1
QuickSort(array, start, end)
if start < end
then do
pivot = Partition(array, start, end)
QuickSort(array, start, pivot - 1)
QuickSort(array, pivot + 1, end)