Search code examples
javaarrayssortingtimsort

Why does this sort in Java 1.8


Taken from Java Puzzlers by Joshua Bloch and Neal Gafter

import java.util.*;

public class BananaBread {
    public static void main(String[] args) {
        Integer[] array = { 3, 1, 4, 1, 5, 9 };
        Arrays.sort(array, new Comparator<Integer>() {
            public int compare(Integer i1, Integer i2) {
                return i1 < i2 ? -1 : (i2 > i1 ? 1 : 0);
            }
        });
        System.out.println(Arrays.toString(array));
    }
}

The expected behaviour is undefined and the text says that it returns [3, 1, 4, 1, 5, 9]. This is true up to Java Version 1.7. However, in Java v. 1.8, the output is the sorted list.

I can see that Timsort is new in Java 1.8, but I'm not sure how the algorithm can function with an inconsistent comparator such as the one given above. Any help or insight into how this can be would be greatly appreciated.


Solution

  • Java 8 uses a modied merge sort. The key line it uses is

    // From TimSort.binarySort
    while (left < right) {
        int mid = (left + right) >>> 1;
        if (c.compare(pivot, a[mid]) < 0)  // compares for less than 0.
            right = mid;
        else
            left = mid + 1;
    }
    

    Note: it only cares about whether you return -1 or 0 (more specifically is < 0, true or false)

    Your comparator is the same as

    return i1 < i2 ? -1 : 0;
    

    so in all the ways that matter for this code it's correct.

    Note: if you change the code like this

    return i1 > i2 ? +1 : 0;
    

    It doesn't sort anything.