Simple Sorts
Efficiency of the Bubble Sort
Both swaps and comparisons are proportional to N2. Because constants don't count in
Big O notation, we can ignore the 2 and the 4 and say that the bubble sort runs in O(N2)
time.
Code:
public void bubbleSort()
{
int out, in;
for(out=nElems-1; out>1; out--) // outer loop (backward)
for(in=0; in<out; in++) // inner loop (forward)
if( a[in] > a[in+1] ) // out of order?
swap(in, in+1); // swap them
} // end bubbleSort()
Efficiency of the Selection Sort
The selection sort performs the same number of comparisons as the bubble sort: N*(N–
1)/2. For 10 data items, this is 45 comparisons. However, 10 items require fewer than 10
swaps. With 100 items, 4,950 comparisons are required, but fewer than 100 swaps. For
large values of N, the comparison times will dominate, so we would have to say that the
selection sort runs in O(N2) time, just as the bubble sort did. However, it is unquestionably
faster because there are so few swaps. For smaller values of N, it may in fact be
considerably faster, especially if the swap times are much larger than the comparison
times.
Code:
public void selectionSort()
{
int out, in, min;
for(out=0; out<nElems-1; out++) // outer loop
{
min = out; // minimum
for(in=out+1; in<nElems; in++) // inner loop
if(a[in] < a[min] ) // if min greater,
min = in; // we have a new min
swap(out, min); // swap them
} // end for(outer) } // end selectionSort()
Efficiency of the Insertion Sort
the insertion sort runs in O(N2) time for random data.
For data that is already sorted or almost sorted, the insertion sort does much better.
When data is in order, the condition in the while loop is never true, so it becomes a
simple statement in the outer loop, which executes N–1 times. In this case the algorithm
runs in O(N) time. If the data is almost sorted, insertion sort runs in almost O(N) time,
which makes it a simple and efficient way to order a file that is only slightly out of order.
However, for data arranged in inverse sorted order, every possible comparison and shift is
carried out, so the insertion sort runs no faster than the bubble sort.
Code:
public void insertionSort()
{
int in, out;
for(out=1; out<nElems; out++) // out is dividing line
{
double temp = a[out]; // remove marked item
in = out; // start shifts at out
while(in>0 && a[in-1] >= temp) // until one is smaller,
{
a[in] = a[in-1]; // shift item right,
--in; // go left one position
}
a[in] = temp; // insert marked item
} // end for
} // end insertionSort()
Stability
Sometimes it matters what happens to data items that happen to have equal keys. For
example, you may have employee data arranged alphabetically by last names. (That is,
the last names were used as key values in the sort.) Now you want to sort the data by zip
code, but you want all the items with the same zip code to continue to be sorted by last
names. You want the algorithm to sort only what needs to be sorted, and leave
everything else in its original order. Some sorting algorithms retain this secondary
ordering; they're said to be stable.
All the algorithms in this chapter are stable.
Comparing the Simple Sorts
There's probably no point in using the bubble sort unless you don't have your algorithm
book handy. The bubble sort is so simple you can write it from memory. Even so, it's
practical only if the amount of data is small.
The selection sort minimizes the number of swaps, but the number of comparisons is still
high. It might be useful when the amount of data is small and swapping data items is very
time-consuming compared with comparing them.
The insertion sort is the most versatile of the three and is the best bet in most situations,
assuming the amount of data is small or the data is almost sorted. For larger amounts of
data, quicksort is generally considered the fastest approach.
We've compared the sorting algorithms in terms of speed. Another consideration for any
algorithm is how much memory space it needs. All three of the algorithms in this chapter
carry out their sort in place, meaning that, beside the initial array, very little extra memory
is required. All the sorts require an extra variable to store an item temporarily while it's
being swapped.