java - Why does this program using Collections.sort only fail for lists of size 32 or more? -
the following program throws following exception:
java.lang.illegalargumentexception: comparison method violates general contract!
i understand problem comparator
. see unable replicate : "comparison method violates general contract!"
i don't understand why fails list
s of size 32 or more. can explain?
class experiment { private static final class myinteger { private final integer num; myinteger(integer num) { this.num = num; } } private static final comparator<myinteger> comparator = (r1, r2) -> { if (r1.num == null || r2.num == null) return 0; return integer.compare(r1.num, r2.num); }; public static void main(string[] args) { myinteger[] array = {new myinteger(0), new myinteger(1), new myinteger(null)}; random random = new random(); (int length = 0;; length++) { (int attempt = 0; attempt < 100000; attempt++) { list<myinteger> list = new arraylist<>(); int[] arr = new int[length]; (int k = 0; k < length; k++) { int rand = random.nextint(3); arr[k] = rand; list.add(array[rand]); } try { collections.sort(list, comparator); } catch (exception e) { system.out.println(arr.length + " " + arrays.tostring(arr)); return; } } } } }
it depends on implementation, in openjdk 8 size of array checked against min_merge, equal 32. avoids call mergelo
/mergehi
throw exception.
from jdk / jdk / openjdk / 7u40-b43 8-b132 7-b147 - 8-b132 / java.util.timsort:
static <t> void sort(t[] a, int lo, int hi, comparator<? super t> c, t[] work, int workbase, int worklen) { assert c != null && != null && lo >= 0 && lo <= hi && hi <= a.length; int nremaining = hi - lo; if (nremaining < 2) return; // arrays of size 0 , 1 sorted // if array small, "mini-timsort" no merges if (nremaining < min_merge) { int initrunlen = countrunandmakeascending(a, lo, hi, c); binarysort(a, lo, hi, lo + initrunlen, c); return; } /** * march on array once, left right, finding natural runs, * extending short natural runs minrun elements, , merging runs * maintain stack invariant. */ timsort<t> ts = new timsort<>(a, c, work, workbase, worklen); int minrun = minrunlength(nremaining); { // identify next run int runlen = countrunandmakeascending(a, lo, hi, c); // if run short, extend min(minrun, nremaining) if (runlen < minrun) { int force = nremaining <= minrun ? nremaining : minrun; binarysort(a, lo, lo + force, lo + runlen, c); runlen = force; } // push run onto pending-run stack, , maybe merge ts.pushrun(lo, runlen); ts.mergecollapse(); // advance find next run lo += runlen; nremaining -= runlen; } while (nremaining != 0); // merge remaining runs complete sort assert lo == hi; ts.mergeforcecollapse(); assert ts.stacksize == 1; }
Comments
Post a Comment