views:

266

answers:

1

I have a couple of questions concerning different implementations of insertion sort.

Implementation 1:

public static void insertionSort(int[] a) {
    for (int i = 1; i < a.length; ++i) {
        int key = a[i];
        int j   = i - 1;

        while (j >= 0 && a[j] > key) {
            a[j + 1] = a[j];
            --j;
        }

        a[j + 1] = key;
    }
}

Implementation 2:

public static void insertionSort(int[] a) {
    for (int i = 1; i < a.length; ++i) {
        for (int j = i; j > 0 && a[j - 1] > a[j]; --j) {
            swap(a, j, j - 1);
        }
    }
}

private static void swap(int[] a, int i, int j) {
    int tmp = a[i];

    a[i] = a[j];
    a[j] = tmp;
}

Here's my first question: One should think that the first version should be a little faster that the second version (because of lesser assignments) but it isn't (or at least the difference it's negligible). But why?

Second, I was wondering that Java's Arrays.sort() method also uses the second approach (maybe because of code reuse because the swap method is used in different places, maybe because it's easier to understand).

Implementation 3 (binaryInsertionSort):

    public static void binaryInsertionSort(int[] a) {
    for (int i = 1; i < a.length; ++i) {
        int pos            = Arrays.binarySearch(a, 0, i, a[i]);
        int insertionPoint = (pos >= 0) ? pos : -pos - 1;

        if (insertionPoint < i) {
            int key = a[i];

            // for (int j = i; i > insertionPoint; --i) {
            //     a[j] = a[j - 1];
            // }
            System.arraycopy(a, insertionPoint, a, insertionPoint + 1, i - insertionPoint);

            a[insertionPoint] = key;
        }
    }
}

Is the binary insertion sort of any practical use, or is it more of a theoretical thing? On small arrays, the other approaches are much faster, and on bigger arrays mergesort/quicksort has a much better performance.

A: 
  1. delete false claim
  2. The number of comparisons in the first two is 1/2*n(n-1), excluding those for the outer loops.
  3. None of these programs make much sense for real work as they stand, because they don't make use of the information at their disposal. For instance, it is easy to add a check to the inner loop to see if any swaps have been made: if not then the array is sorted, and you can finish, perhaps saving most of the work. In practice, these kinds of consideration can dominate the average case.

Postscript Missed the question about Java: I understand that Java's sort is a pretty complex algorithm, which uses a lot of special cases, such as specialised sorting cases for small arrays, and using quicksort to do its heavy lifting.

Charles Stewart
No, the first two are insertion sorts (assuming they aren't buggy). Insertion sort performs n - 1 passes, and after k passes the first k+1 elements of the array are sorted. No early exit is possible in the code given, because for instance the last element isn't even visited until the last execution of the outer loop. Bubble sort visits the whole array on each pass, but doesn't fully sort what it leaves behind.
Steve Jessop
@Steve: Ouch, yes, wrt insertion sort. No, re bubblesort - the inner loop normally permutes out the greatest or least value, and so need not visit the whole array on subsequent passes, and can have the same number of comparisons as the naive insertion sort.
Charles Stewart
Sorry, you're right, I only mentioned visiting the whole array as a contrast with insertion sort, to show why early exit differs, not to estimate running time. I should have said, "bubble sort visits the whole array on the first pass", or "bubble sort visits the whole unsorted portion of the array on each pass", or some such.
Steve Jessop