Selection sort, heap sort, insertion sort, shell sort.
Selection-based sorting algorithms take the following steps:
For each key where and :
Search the maximum key where .
Swap and
The complexities differ by different search algorithms:
Algorithm
Search
Compare
Swap
Selection Sort
Heap Sort
Selection Sort uses linear search to find the minimum (or maximum) key, whereas Heap Sort turns the input array into a heap, so the search complexity becomes instead of .
Can the search be faster than ?
Let us create the SelectionSort
class inheriting AbstractSort
:
Let us then override the sort()
method:
How does the
sort()
method work withComparator.reverseOrder()
?
Let us create the HeapSort
class inheriting AbstractSort
:
Before we override the sort()
method, let us define the following helper methods:
L1-7
: finds the right position of the k
'th key by using the sink operation.
L9-11
: finds the parent index of the k
'th key given the beginning index.
L13-15
: finds the left child index of the k
'th key given the beginning index.
How is this
sink()
method different from the one in theBinaryHeap
class?
Finally, we override the sort()
method:
What is the worst-case scenario for Selection Sort and Heap Sort?
Insertion-based sorting algorithms take the following steps:
The complexities differ by different sequences:
Algorithm
Sequence
Compare
Swap
Insertion Sort
Adjacent
Shell Sort
Knuth
Let us create the InsertionSort
class inheriting AbstractSort
:
Let us then define an auxiliary method, sort()
:
L6
: swaps the two keys.
Given the auxiliary method, the sort()
method can be defined as follows where h = 1
:
How many swaps does Insertion Sort make for the following array?
[7, 1, 2, 3, 4, 5, 6, 14, 8, 9, 10, 11, 12, 13, 0]
Shell Sort groups keys whose gap is defined by a particular gap sequence:
For the above example, by using the Hibbard sequence, it first groups keys whose gap is 7:[7, 14, 0], [1, 8], [2, 9], [3, 10], [4, 11], [5, 12], [6, 13]
It then sorts each group using Insertion Sort, which results in the following array:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
The above procedure is repeated for gaps 3 and 1; however, the array is already sorted, so no more swapping is necessary.
Let us create an abstract class, ShellSort
, inheriting AbstractSort
:
L2
: stores a particular gap sequence.
L7
: pre-populate the gap sequence that can handle the input size up to 10000
.
Then, let us define two abstract methods, populateSequence()
and getSequenceStartIndex()
:
L5
: populates a particular sequence for the input size n
.
L11
: returns the index of the first gap to be used given the input size n
.
Let us then override the sort()
method:
L4
: should not re-populate the sequence unless it has to.
L7
: sorts the gap group by using the auxiliary method.
Let us create the ShellSortKnuth
class that populates the Knuth Sequence for ShellSort
:
The two abstract methods can be overridden as follows:
The codes for unit testing and benchmarking are available in SortTest
:
L3-12
:
L3
: iterates all keys within the range .
L4-9
: finds the index of the maximum key within the range .
L11
: swaps the maximum key with the last key in the range .
L4-5
: turns the input array into a heap :
L4
: iterates from the parent of the key in the ending index .
L5
: sinks the key .
L8-11
: selection sort :
L8
: iterates all keys within the range .
L9
: swaps the maximum key with the beginning key in the range .
L10
: sinks to heapify .
For each key where and :
Keep swapping and until .
L4
: iterates keys in the input array .
L5
: compares keys in the sublist of the input array .
Knuth:
Hibbard:
Pratt:
Shell: , where
L6
: iterates the sequence where is the number of gaps in the sequence.
L2
: populates the Knuth sequence up to the gap .
L13
: returns the index of the first key .
Why should we use as the largest gap in the sequence?