/* * Carrot2 project. * * Copyright (C) 2002-2016, Dawid Weiss, Stanisław Osiński. * All rights reserved. * * Refer to the full license file "carrot2.LICENSE" * in the root folder of the repository checkout or at: * http://www.carrot2.org/carrot2.LICENSE */ package org.carrot2.mahout.math; import java.util.Arrays; import java.util.Comparator; import org.carrot2.mahout.math.function.ByteComparator; import org.carrot2.mahout.math.function.CharComparator; import org.carrot2.mahout.math.function.DoubleComparator; import org.carrot2.mahout.math.function.FloatComparator; import org.carrot2.mahout.math.function.IntComparator; import org.carrot2.mahout.math.function.LongComparator; import org.carrot2.mahout.math.function.ShortComparator; public final class Sorting { /* Specifies when to switch to insertion sort */ private static final int SIMPLE_LENGTH = 7; static final int SMALL = 7; private Sorting() { /* empty */ } public static int binarySearchFromTo(byte[] array, byte value, int from, int to) { int mid = -1; while (from <= to) { mid = (from + to) >>> 1; if (value > array[mid]) { from = mid + 1; } else if (value == array[mid]) { return mid; } else { to = mid - 1; } } if (mid < 0) { return -1; } return -mid - (value < array[mid] ? 1 : 2); } public static int binarySearchFromTo(char[] array, char value, int from, int to) { int mid = -1; while (from <= to) { mid = (from + to) >>> 1; if (value > array[mid]) { from = mid + 1; } else if (value == array[mid]) { return mid; } else { to = mid - 1; } } if (mid < 0) { return -1; } return -mid - (value < array[mid] ? 1 : 2); } public static int binarySearchFromTo(double[] array, double value, int from, int to) { long longBits = Double.doubleToLongBits(value); int mid = -1; while (from <= to) { mid = (from + to) >>> 1; if (lessThan(array[mid], value)) { from = mid + 1; } else if (longBits == Double.doubleToLongBits(array[mid])) { return mid; } else { to = mid - 1; } } if (mid < 0) { return -1; } return -mid - (lessThan(value, array[mid]) ? 1 : 2); } public static int binarySearchFromTo(float[] array, float value, int from, int to) { int intBits = Float.floatToIntBits(value); int mid = -1; while (from <= to) { mid = (from + to) >>> 1; if (lessThan(array[mid], value)) { from = mid + 1; } else if (intBits == Float.floatToIntBits(array[mid])) { return mid; } else { to = mid - 1; } } if (mid < 0) { return -1; } return -mid - (lessThan(value, array[mid]) ? 1 : 2); } public static int binarySearchFromTo(int[] array, int value, int from, int to) { int mid = -1; while (from <= to) { mid = (from + to) >>> 1; if (value > array[mid]) { from = mid + 1; } else if (value == array[mid]) { return mid; } else { to = mid - 1; } } if (mid < 0) { return -1; } return -mid - (value < array[mid] ? 1 : 2); } public static int binarySearchFromTo(long[] array, long value, int from, int to) { int mid = -1; while (from <= to) { mid = (from + to) >>> 1; if (value > array[mid]) { from = mid + 1; } else if (value == array[mid]) { return mid; } else { to = mid - 1; } } if (mid < 0) { return -1; } return -mid - (value < array[mid] ? 1 : 2); } public static <T extends Comparable<T>> int binarySearchFromTo(T[] array, T object, int from, int to) { if (array.length == 0) { return -1; } int mid = 0, result = 0; while (from <= to) { mid = (from + to) >>> 1; if ((result = array[mid].compareTo(object)) < 0) { from = mid + 1; } else if (result == 0) { return mid; } else { to = mid - 1; } } return -mid - (result >= 0 ? 1 : 2); } public static <T> int binarySearchFromTo(T[] array, T object, int from, int to, Comparator<? super T> comparator) { int mid = 0, result = 0; while (from <= to) { mid = (from + to) >>> 1; if ((result = comparator.compare(array[mid], object)) < 0) { from = mid + 1; } else if (result == 0) { return mid; } else { to = mid - 1; } } return -mid - (result >= 0 ? 1 : 2); } public static int binarySearchFromTo(short[] array, short value, int from, int to) { int mid = -1; while (from <= to) { mid = (from + to) >>> 1; if (value > array[mid]) { from = mid + 1; } else if (value == array[mid]) { return mid; } else { to = mid - 1; } } if (mid < 0) { return -1; } return -mid - (value < array[mid] ? 1 : 2); } private static boolean lessThan(double double1, double double2) { // A slightly specialized version of // Double.compare(double1, double2) < 0. // Non-zero and non-NaN checking. if (double1 < double2) { return true; } if (double1 > double2) { return false; } if (double1 == double2 && double1 != 0.0) { return false; } // NaNs are equal to other NaNs and larger than any other double. if (Double.isNaN(double1)) { return false; } else if (Double.isNaN(double2)) { return true; } // Deal with +0.0 and -0.0. long d1 = Double.doubleToRawLongBits(double1); long d2 = Double.doubleToRawLongBits(double2); return d1 < d2; } private static boolean lessThan(float float1, float float2) { // A slightly specialized version of Float.compare(float1, float2) < 0. // Non-zero and non-NaN checking. if (float1 < float2) { return true; } if (float1 > float2) { return false; } if (float1 == float2 && float1 != 0.0f) { return false; } // NaNs are equal to other NaNs and larger than any other float if (Float.isNaN(float1)) { return false; } else if (Float.isNaN(float2)) { return true; } // Deal with +0.0 and -0.0 int f1 = Float.floatToRawIntBits(float1); int f2 = Float.floatToRawIntBits(float2); return f1 < f2; } private static <T> int med3(T[] array, int a, int b, int c, Comparator<T> comp) { T x = array[a], y = array[b], z = array[c]; int comparisonxy = comp.compare(x, y); int comparisonxz = comp.compare(x, z); int comparisonyz = comp.compare(y, z); return comparisonxy < 0 ? (comparisonyz < 0 ? b : (comparisonxz < 0 ? c : a)) : (comparisonyz > 0 ? b : (comparisonxz > 0 ? c : a)); } private static int med3(byte[] array, int a, int b, int c, ByteComparator comp) { byte x = array[a], y = array[b], z = array[c]; int comparisonxy = comp.compare(x, y); int comparisonxz = comp.compare(x, z); int comparisonyz = comp.compare(y, z); return comparisonxy < 0 ? (comparisonyz < 0 ? b : (comparisonxz < 0 ? c : a)) : (comparisonyz > 0 ? b : (comparisonxz > 0 ? c : a)); } private static int med3(char[] array, int a, int b, int c, CharComparator comp) { char x = array[a], y = array[b], z = array[c]; int comparisonxy = comp.compare(x, y); int comparisonxz = comp.compare(x, z); int comparisonyz = comp.compare(y, z); return comparisonxy < 0 ? (comparisonyz < 0 ? b : (comparisonxz < 0 ? c : a)) : (comparisonyz > 0 ? b : (comparisonxz > 0 ? c : a)); } private static int med3(double[] array, int a, int b, int c, DoubleComparator comp) { double x = array[a], y = array[b], z = array[c]; int comparisonxy = comp.compare(x, y); int comparisonxz = comp.compare(x, z); int comparisonyz = comp.compare(y, z); return comparisonxy < 0 ? (comparisonyz < 0 ? b : (comparisonxz < 0 ? c : a)) : (comparisonyz > 0 ? b : (comparisonxz > 0 ? c : a)); } private static int med3(float[] array, int a, int b, int c, FloatComparator comp) { float x = array[a], y = array[b], z = array[c]; int comparisonxy = comp.compare(x, y); int comparisonxz = comp.compare(x, z); int comparisonyz = comp.compare(y, z); return comparisonxy < 0 ? (comparisonyz < 0 ? b : (comparisonxz < 0 ? c : a)) : (comparisonyz > 0 ? b : (comparisonxz > 0 ? c : a)); } private static int med3(int[] array, int a, int b, int c, IntComparator comp) { int x = array[a], y = array[b], z = array[c]; int comparisonxy = comp.compare(x, y); int comparisonxz = comp.compare(x, z); int comparisonyz = comp.compare(y, z); return comparisonxy < 0 ? (comparisonyz < 0 ? b : (comparisonxz < 0 ? c : a)) : (comparisonyz > 0 ? b : (comparisonxz > 0 ? c : a)); } private static int med3(int a, int b, int c, IntComparator comp) { int comparisonab = comp.compare(a, b); int comparisonac = comp.compare(a, c); int comparisonbc = comp.compare(b, c); return comparisonab < 0 ? (comparisonbc < 0 ? b : (comparisonac < 0 ? c : a)) : (comparisonbc > 0 ? b : (comparisonac > 0 ? c : a)); } private static int med3(long[] array, int a, int b, int c, LongComparator comp) { long x = array[a], y = array[b], z = array[c]; int comparisonxy = comp.compare(x, y); int comparisonxz = comp.compare(x, z); int comparisonyz = comp.compare(y, z); return comparisonxy < 0 ? (comparisonyz < 0 ? b : (comparisonxz < 0 ? c : a)) : (comparisonyz > 0 ? b : (comparisonxz > 0 ? c : a)); } private static int med3(short[] array, int a, int b, int c, ShortComparator comp) { short x = array[a], y = array[b], z = array[c]; int comparisonxy = comp.compare(x, y); int comparisonxz = comp.compare(x, z); int comparisonyz = comp.compare(y, z); return comparisonxy < 0 ? (comparisonyz < 0 ? b : (comparisonxz < 0 ? c : a)) : (comparisonyz > 0 ? b : (comparisonxz > 0 ? c : a)); } public static void quickSort(byte[] array, int start, int end, ByteComparator comp) { if (array == null) { throw new NullPointerException(); } checkBounds(array.length, start, end); quickSort0(start, end, array, comp); } private static void checkBounds(int arrLength, int start, int end) { if (start > end) { // K0033=Start index ({0}) is greater than end index ({1}) throw new IllegalArgumentException("Start index " + start + " is greater than end index " + end); } if (start < 0) { throw new ArrayIndexOutOfBoundsException("Array index out of range " + start); } if (end > arrLength) { throw new ArrayIndexOutOfBoundsException("Array index out of range " + end); } } private static void quickSort0(int start, int end, byte[] array, ByteComparator comp) { byte temp; int length = end - start; if (length < 7) { for (int i = start + 1; i < end; i++) { for (int j = i; j > start && comp.compare(array[j - 1], array[j]) > 0; j--) { temp = array[j]; array[j] = array[j - 1]; array[j - 1] = temp; } } return; } int middle = (start + end) / 2; if (length > 7) { int bottom = start; int top = end - 1; if (length > 40) { length /= 8; bottom = med3(array, bottom, bottom + length, bottom + (2 * length), comp); middle = med3(array, middle - length, middle, middle + length, comp); top = med3(array, top - (2 * length), top - length, top, comp); } middle = med3(array, bottom, middle, top, comp); } byte partionValue = array[middle]; int a, b, c, d; a = b = start; c = d = end - 1; while (true) { int comparison; while (b <= c && (comparison = comp.compare(array[b], partionValue)) <= 0) { if (comparison == 0) { temp = array[a]; array[a++] = array[b]; array[b] = temp; } b++; } while (c >= b && (comparison = comp.compare(array[c], partionValue)) >= 0) { if (comparison == 0) { temp = array[c]; array[c] = array[d]; array[d--] = temp; } c--; } if (b > c) { break; } temp = array[b]; array[b++] = array[c]; array[c--] = temp; } length = a - start < b - a ? a - start : b - a; int l = start; int h = b - length; while (length-- > 0) { temp = array[l]; array[l++] = array[h]; array[h++] = temp; } length = d - c < end - 1 - d ? d - c : end - 1 - d; l = b; h = end - length; while (length-- > 0) { temp = array[l]; array[l++] = array[h]; array[h++] = temp; } if ((length = b - a) > 0) { quickSort0(start, start + length, array, comp); } if ((length = d - c) > 0) { quickSort0(end - length, end, array, comp); } } public static void quickSort(int start, int end, IntComparator comp, Swapper swap) { checkBounds(end+1, start, end); quickSort0(start, end, comp, swap); } private static void quickSort0(int start, int end, IntComparator comp, Swapper swap) { int length = end - start; if (length < 7) { insertionSort(start, end, comp, swap); return; } int middle = (start + end) / 2; if (length > 7) { int bottom = start; int top = end - 1; if (length > 40) { // for lots of data, bottom, middle and top are medians near the beginning, middle or end of the data int skosh = length / 8; bottom = med3(bottom, bottom + skosh, bottom + (2 * skosh), comp); middle = med3(middle - skosh, middle, middle + skosh, comp); top = med3(top - (2 * skosh), top - skosh, top, comp); } middle = med3(bottom, middle, top, comp); } int partitionIndex = middle; // an index, not a value. // regions from a to b and from c to d are what we will recursively sort int a, b, c, d; a = b = start; c = d = end - 1; while (b <= c) { // copy all values equal to the partition value to before a..b. In the process, advance b // as long as values less than the partition or equal are found, also stop when a..b collides with c..d int comparison; while (b <= c && (comparison = comp.compare(b, partitionIndex)) <= 0) { if (comparison == 0) { if (a == partitionIndex) { partitionIndex = b; } else if (b == partitionIndex) { partitionIndex = a; } swap.swap(a, b); a++; } b++; } // at this point [start..a) has partition values, [a..b) has values < partition // also, either b>c or v[b] > partition value while (c >= b && (comparison = comp.compare(c, partitionIndex)) >= 0) { if (comparison == 0) { if (c == partitionIndex) { partitionIndex = d; } else if (d == partitionIndex) { partitionIndex = c; } swap.swap(c, d); d--; } c--; } // now we also know that [d..end] contains partition values, // [c..d) contains values > partition value // also, either b>c or (v[b] > partition OR v[c] < partition) if (b <= c) { // v[b] > partition OR v[c] < partition // swapping will let us continue to grow the two regions if (c == partitionIndex) { partitionIndex = b; } else if (b == partitionIndex) { partitionIndex = d; } swap.swap(b, c); b++; c--; } } // now we know // b = c+1 // [start..a) and [d..end) contain partition value // all of [a..b) are less than partition // all of [c..d) are greater than partition // shift [a..b) to beginning length = Math.min(a - start, b - a); int l = start; int h = b - length; while (length-- > 0) { swap.swap(l, h); l++; h++; } // shift [c..d) to end length = Math.min(d - c, end - 1 - d); l = b; h = end - length; while (length-- > 0) { swap.swap(l, h); l++; h++; } // recurse left and right length = b - a; if (length > 0) { quickSort0(start, start + length, comp, swap); } length = d - c; if (length > 0) { quickSort0(end - length, end, comp, swap); } } private static void insertionSort(int start, int end, IntComparator comp, Swapper swap) { for (int i = start + 1; i < end; i++) { for (int j = i; j > start && comp.compare(j - 1, j) > 0; j--) { swap.swap(j - 1, j); } } } public static void quickSort(char[] array, int start, int end, CharComparator comp) { if (array == null) { throw new NullPointerException(); } checkBounds(array.length, start, end); quickSort0(start, end, array, comp); } private static void quickSort0(int start, int end, char[] array, CharComparator comp) { char temp; int length = end - start; if (length < 7) { for (int i = start + 1; i < end; i++) { for (int j = i; j > start && comp.compare(array[j - 1], array[j]) > 0; j--) { temp = array[j]; array[j] = array[j - 1]; array[j - 1] = temp; } } return; } int middle = (start + end) / 2; if (length > 7) { int bottom = start; int top = end - 1; if (length > 40) { length /= 8; bottom = med3(array, bottom, bottom + length, bottom + (2 * length), comp); middle = med3(array, middle - length, middle, middle + length, comp); top = med3(array, top - (2 * length), top - length, top, comp); } middle = med3(array, bottom, middle, top, comp); } char partionValue = array[middle]; int a, b, c, d; a = b = start; c = d = end - 1; while (true) { int comparison; while (b <= c && (comparison = comp.compare(array[b], partionValue)) <= 0) { if (comparison == 0) { temp = array[a]; array[a++] = array[b]; array[b] = temp; } b++; } while (c >= b && (comparison = comp.compare(array[c], partionValue)) >= 0) { if (comparison == 0) { temp = array[c]; array[c] = array[d]; array[d--] = temp; } c--; } if (b > c) { break; } temp = array[b]; array[b++] = array[c]; array[c--] = temp; } length = a - start < b - a ? a - start : b - a; int l = start; int h = b - length; while (length-- > 0) { temp = array[l]; array[l++] = array[h]; array[h++] = temp; } length = d - c < end - 1 - d ? d - c : end - 1 - d; l = b; h = end - length; while (length-- > 0) { temp = array[l]; array[l++] = array[h]; array[h++] = temp; } if ((length = b - a) > 0) { quickSort0(start, start + length, array, comp); } if ((length = d - c) > 0) { quickSort0(end - length, end, array, comp); } } public static void quickSort(double[] array, int start, int end, DoubleComparator comp) { if (array == null) { throw new NullPointerException(); } checkBounds(array.length, start, end); quickSort0(start, end, array, comp); } private static void quickSort0(int start, int end, double[] array, DoubleComparator comp) { double temp; int length = end - start; if (length < 7) { for (int i = start + 1; i < end; i++) { for (int j = i; j > start && comp.compare(array[j], array[j - 1]) < 0; j--) { temp = array[j]; array[j] = array[j - 1]; array[j - 1] = temp; } } return; } int middle = (start + end) / 2; if (length > 7) { int bottom = start; int top = end - 1; if (length > 40) { length /= 8; bottom = med3(array, bottom, bottom + length, bottom + (2 * length), comp); middle = med3(array, middle - length, middle, middle + length, comp); top = med3(array, top - (2 * length), top - length, top, comp); } middle = med3(array, bottom, middle, top, comp); } double partionValue = array[middle]; int a, b, c, d; a = b = start; c = d = end - 1; while (true) { int comparison; while (b <= c && (comparison = comp.compare(partionValue, array[b])) >= 0) { if (comparison == 0) { temp = array[a]; array[a++] = array[b]; array[b] = temp; } b++; } while (c >= b && (comparison = comp.compare(array[c], partionValue)) >= 0) { if (comparison == 0) { temp = array[c]; array[c] = array[d]; array[d--] = temp; } c--; } if (b > c) { break; } temp = array[b]; array[b++] = array[c]; array[c--] = temp; } length = a - start < b - a ? a - start : b - a; int l = start; int h = b - length; while (length-- > 0) { temp = array[l]; array[l++] = array[h]; array[h++] = temp; } length = d - c < end - 1 - d ? d - c : end - 1 - d; l = b; h = end - length; while (length-- > 0) { temp = array[l]; array[l++] = array[h]; array[h++] = temp; } if ((length = b - a) > 0) { quickSort0(start, start + length, array, comp); } if ((length = d - c) > 0) { quickSort0(end - length, end, array, comp); } } public static void quickSort(float[] array, int start, int end, FloatComparator comp) { if (array == null) { throw new NullPointerException(); } checkBounds(array.length, start, end); quickSort0(start, end, array, comp); } private static void quickSort0(int start, int end, float[] array, FloatComparator comp) { float temp; int length = end - start; if (length < 7) { for (int i = start + 1; i < end; i++) { for (int j = i; j > start && comp.compare(array[j], array[j - 1]) < 0; j--) { temp = array[j]; array[j] = array[j - 1]; array[j - 1] = temp; } } return; } int middle = (start + end) / 2; if (length > 7) { int bottom = start; int top = end - 1; if (length > 40) { length /= 8; bottom = med3(array, bottom, bottom + length, bottom + (2 * length), comp); middle = med3(array, middle - length, middle, middle + length, comp); top = med3(array, top - (2 * length), top - length, top, comp); } middle = med3(array, bottom, middle, top, comp); } float partionValue = array[middle]; int a, b, c, d; a = b = start; c = d = end - 1; while (true) { int comparison; while (b <= c && (comparison = comp.compare(partionValue, array[b])) >= 0) { if (comparison == 0) { temp = array[a]; array[a++] = array[b]; array[b] = temp; } b++; } while (c >= b && (comparison = comp.compare(array[c], partionValue)) >= 0) { if (comparison == 0) { temp = array[c]; array[c] = array[d]; array[d--] = temp; } c--; } if (b > c) { break; } temp = array[b]; array[b++] = array[c]; array[c--] = temp; } length = a - start < b - a ? a - start : b - a; int l = start; int h = b - length; while (length-- > 0) { temp = array[l]; array[l++] = array[h]; array[h++] = temp; } length = d - c < end - 1 - d ? d - c : end - 1 - d; l = b; h = end - length; while (length-- > 0) { temp = array[l]; array[l++] = array[h]; array[h++] = temp; } if ((length = b - a) > 0) { quickSort0(start, start + length, array, comp); } if ((length = d - c) > 0) { quickSort0(end - length, end, array, comp); } } public static void quickSort(int[] array, int start, int end, IntComparator comp) { if (array == null) { throw new NullPointerException(); } checkBounds(array.length, start, end); quickSort0(start, end, array, comp); } private static void quickSort0(int start, int end, int[] array, IntComparator comp) { int temp; int length = end - start; if (length < 7) { for (int i = start + 1; i < end; i++) { for (int j = i; j > start && comp.compare(array[j - 1], array[j]) > 0; j--) { temp = array[j]; array[j] = array[j - 1]; array[j - 1] = temp; } } return; } int middle = (start + end) / 2; if (length > 7) { int bottom = start; int top = end - 1; if (length > 40) { length /= 8; bottom = med3(array, bottom, bottom + length, bottom + (2 * length), comp); middle = med3(array, middle - length, middle, middle + length, comp); top = med3(array, top - (2 * length), top - length, top, comp); } middle = med3(array, bottom, middle, top, comp); } int partionValue = array[middle]; int a, b, c, d; a = b = start; c = d = end - 1; while (true) { int comparison; while (b <= c && (comparison = comp.compare(array[b], partionValue)) <= 0) { if (comparison == 0) { temp = array[a]; array[a++] = array[b]; array[b] = temp; } b++; } while (c >= b && (comparison = comp.compare(array[c], partionValue)) >= 0) { if (comparison == 0) { temp = array[c]; array[c] = array[d]; array[d--] = temp; } c--; } if (b > c) { break; } temp = array[b]; array[b++] = array[c]; array[c--] = temp; } length = a - start < b - a ? a - start : b - a; int l = start; int h = b - length; while (length-- > 0) { temp = array[l]; array[l++] = array[h]; array[h++] = temp; } length = d - c < end - 1 - d ? d - c : end - 1 - d; l = b; h = end - length; while (length-- > 0) { temp = array[l]; array[l++] = array[h]; array[h++] = temp; } if ((length = b - a) > 0) { quickSort0(start, start + length, array, comp); } if ((length = d - c) > 0) { quickSort0(end - length, end, array, comp); } } public static void quickSort(long[] array, int start, int end, LongComparator comp) { if (array == null) { throw new NullPointerException(); } checkBounds(array.length, start, end); quickSort0(start, end, array, comp); } private static void quickSort0(int start, int end, long[] array, LongComparator comp) { long temp; int length = end - start; if (length < 7) { for (int i = start + 1; i < end; i++) { for (int j = i; j > start && comp.compare(array[j - 1], array[j]) > 0; j--) { temp = array[j]; array[j] = array[j - 1]; array[j - 1] = temp; } } return; } int middle = (start + end) / 2; if (length > 7) { int bottom = start; int top = end - 1; if (length > 40) { length /= 8; bottom = med3(array, bottom, bottom + length, bottom + (2 * length), comp); middle = med3(array, middle - length, middle, middle + length, comp); top = med3(array, top - (2 * length), top - length, top, comp); } middle = med3(array, bottom, middle, top, comp); } long partionValue = array[middle]; int a, b, c, d; a = b = start; c = d = end - 1; while (true) { int comparison; while (b <= c && (comparison = comp.compare(array[b], partionValue)) <= 0) { if (comparison == 0) { temp = array[a]; array[a++] = array[b]; array[b] = temp; } b++; } while (c >= b && (comparison = comp.compare(array[c], partionValue)) >= 0) { if (comparison == 0) { temp = array[c]; array[c] = array[d]; array[d--] = temp; } c--; } if (b > c) { break; } temp = array[b]; array[b++] = array[c]; array[c--] = temp; } length = a - start < b - a ? a - start : b - a; int l = start; int h = b - length; while (length-- > 0) { temp = array[l]; array[l++] = array[h]; array[h++] = temp; } length = d - c < end - 1 - d ? d - c : end - 1 - d; l = b; h = end - length; while (length-- > 0) { temp = array[l]; array[l++] = array[h]; array[h++] = temp; } if ((length = b - a) > 0) { quickSort0(start, start + length, array, comp); } if ((length = d - c) > 0) { quickSort0(end - length, end, array, comp); } } public static <T> void quickSort(T[] array, int start, int end, Comparator<T> comp) { if (array == null) { throw new NullPointerException(); } checkBounds(array.length, start, end); quickSort0(start, end, array, comp); } private static final class ComparableAdaptor<T extends Comparable<? super T>> implements Comparator<T> { @Override public int compare(T o1, T o2) { return o1.compareTo(o2); } } public static <T extends Comparable<? super T>> void quickSort(T[] array, int start, int end) { quickSort(array, start, end, new ComparableAdaptor<T>()); } private static <T> void quickSort0(int start, int end, T[] array, Comparator<T> comp) { T temp; int length = end - start; if (length < 7) { for (int i = start + 1; i < end; i++) { for (int j = i; j > start && comp.compare(array[j - 1], array[j]) > 0; j--) { temp = array[j]; array[j] = array[j - 1]; array[j - 1] = temp; } } return; } int middle = (start + end) / 2; if (length > 7) { int bottom = start; int top = end - 1; if (length > 40) { length /= 8; bottom = med3(array, bottom, bottom + length, bottom + (2 * length), comp); middle = med3(array, middle - length, middle, middle + length, comp); top = med3(array, top - (2 * length), top - length, top, comp); } middle = med3(array, bottom, middle, top, comp); } T partionValue = array[middle]; int a, b, c, d; a = b = start; c = d = end - 1; while (true) { int comparison; while (b <= c && (comparison = comp.compare(array[b], partionValue)) <= 0) { if (comparison == 0) { temp = array[a]; array[a++] = array[b]; array[b] = temp; } b++; } while (c >= b && (comparison = comp.compare(array[c], partionValue)) >= 0) { if (comparison == 0) { temp = array[c]; array[c] = array[d]; array[d--] = temp; } c--; } if (b > c) { break; } temp = array[b]; array[b++] = array[c]; array[c--] = temp; } length = a - start < b - a ? a - start : b - a; int l = start; int h = b - length; while (length-- > 0) { temp = array[l]; array[l++] = array[h]; array[h++] = temp; } length = d - c < end - 1 - d ? d - c : end - 1 - d; l = b; h = end - length; while (length-- > 0) { temp = array[l]; array[l++] = array[h]; array[h++] = temp; } if ((length = b - a) > 0) { quickSort0(start, start + length, array, comp); } if ((length = d - c) > 0) { quickSort0(end - length, end, array, comp); } } public static void quickSort(short[] array, int start, int end, ShortComparator comp) { if (array == null) { throw new NullPointerException(); } checkBounds(array.length, start, end); quickSort0(start, end, array, comp); } private static void quickSort0(int start, int end, short[] array, ShortComparator comp) { short temp; int length = end - start; if (length < 7) { for (int i = start + 1; i < end; i++) { for (int j = i; j > start && comp.compare(array[j - 1], array[j]) > 0; j--) { temp = array[j]; array[j] = array[j - 1]; array[j - 1] = temp; } } return; } int middle = (start + end) / 2; if (length > 7) { int bottom = start; int top = end - 1; if (length > 40) { length /= 8; bottom = med3(array, bottom, bottom + length, bottom + (2 * length), comp); middle = med3(array, middle - length, middle, middle + length, comp); top = med3(array, top - (2 * length), top - length, top, comp); } middle = med3(array, bottom, middle, top, comp); } short partionValue = array[middle]; int a, b, c, d; a = b = start; c = d = end - 1; while (true) { int comparison; while (b <= c && (comparison = comp.compare(array[b], partionValue)) < 0) { if (comparison == 0) { temp = array[a]; array[a++] = array[b]; array[b] = temp; } b++; } while (c >= b && (comparison = comp.compare(array[c], partionValue)) > 0) { if (comparison == 0) { temp = array[c]; array[c] = array[d]; array[d--] = temp; } c--; } if (b > c) { break; } temp = array[b]; array[b++] = array[c]; array[c--] = temp; } length = a - start < b - a ? a - start : b - a; int l = start; int h = b - length; while (length-- > 0) { temp = array[l]; array[l++] = array[h]; array[h++] = temp; } length = d - c < end - 1 - d ? d - c : end - 1 - d; l = b; h = end - length; while (length-- > 0) { temp = array[l]; array[l++] = array[h]; array[h++] = temp; } if ((length = b - a) > 0) { quickSort0(start, start + length, array, comp); } if ((length = d - c) > 0) { quickSort0(end - length, end, array, comp); } } @SuppressWarnings("unchecked") // required to make the temp array work, afaict. public static <T> void mergeSort(T[] array, int start, int end, Comparator<T> comp) { checkBounds(array.length, start, end); int length = end - start; if (length <= 0) { return; } T[] out = (T[]) new Object[array.length]; System.arraycopy(array, start, out, start, length); mergeSort(out, array, start, end, comp); } public static <T extends Comparable<? super T>> void mergeSort(T[] array, int start, int end) { mergeSort(array, start, end, new ComparableAdaptor<T>()); } private static <T> void mergeSort(T[] in, T[] out, int start, int end, Comparator<T> c) { int len = end - start; // use insertion sort for small arrays if (len <= SIMPLE_LENGTH) { for (int i = start + 1; i < end; i++) { T current = out[i]; T prev = out[i - 1]; if (c.compare(prev, current) > 0) { int j = i; do { out[j--] = prev; } while (j > start && (c.compare(prev = out[j - 1], current) > 0)); out[j] = current; } } return; } int med = (end + start) >>> 1; mergeSort(out, in, start, med, c); mergeSort(out, in, med, end, c); // merging // if arrays are already sorted - no merge if (c.compare(in[med - 1], in[med]) <= 0) { System.arraycopy(in, start, out, start, len); return; } int r = med, i = start; // use merging with exponential search do { T fromVal = in[start]; T rVal = in[r]; if (c.compare(fromVal, rVal) <= 0) { int l_1 = find(in, rVal, -1, start + 1, med - 1, c); int toCopy = l_1 - start + 1; System.arraycopy(in, start, out, i, toCopy); i += toCopy; out[i++] = rVal; r++; start = l_1 + 1; } else { int r_1 = find(in, fromVal, 0, r + 1, end - 1, c); int toCopy = r_1 - r + 1; System.arraycopy(in, r, out, i, toCopy); i += toCopy; out[i++] = fromVal; start++; r = r_1 + 1; } } while ((end - r) > 0 && (med - start) > 0); // copy rest of array if ((end - r) <= 0) { System.arraycopy(in, start, out, i, med - start); } else { System.arraycopy(in, r, out, i, end - r); } } private static <T> int find(T[] arr, T val, int bnd, int l, int r, Comparator<T> c) { int m = l; int d = 1; while (m <= r) { if (c.compare(val, arr[m]) > bnd) { l = m + 1; } else { r = m - 1; break; } m += d; d <<= 1; } while (l <= r) { m = (l + r) >>> 1; if (c.compare(val, arr[m]) > bnd) { l = m + 1; } else { r = m - 1; } } return l - 1; } private static final ByteComparator naturalByteComparison = new ByteComparator() { @Override public int compare(byte o1, byte o2) { return o1 - o2; }}; public static void mergeSort(byte[] array, int start, int end) { mergeSort(array, start, end, naturalByteComparison); } public static void mergeSort(byte[] array, int start, int end, ByteComparator comp) { checkBounds(array.length, start, end); byte[] out = Arrays.copyOf(array, array.length); mergeSort(out, array, start, end, comp); } private static void mergeSort(byte[] in, byte[] out, int start, int end, ByteComparator c) { int len = end - start; // use insertion sort for small arrays if (len <= SIMPLE_LENGTH) { for (int i = start + 1; i < end; i++) { byte current = out[i]; byte prev = out[i - 1]; if (c.compare(prev, current) > 0) { int j = i; do { out[j--] = prev; } while (j > start && (c.compare(prev = out[j - 1], current) > 0)); out[j] = current; } } return; } int med = (end + start) >>> 1; mergeSort(out, in, start, med, c); mergeSort(out, in, med, end, c); // merging // if arrays are already sorted - no merge if (c.compare(in[med - 1], in[med]) <= 0) { System.arraycopy(in, start, out, start, len); return; } int r = med, i = start; // use merging with exponential search do { byte fromVal = in[start]; byte rVal = in[r]; if (c.compare(fromVal, rVal) <= 0) { int l_1 = find(in, rVal, -1, start + 1, med - 1, c); int toCopy = l_1 - start + 1; System.arraycopy(in, start, out, i, toCopy); i += toCopy; out[i++] = rVal; r++; start = l_1 + 1; } else { int r_1 = find(in, fromVal, 0, r + 1, end - 1, c); int toCopy = r_1 - r + 1; System.arraycopy(in, r, out, i, toCopy); i += toCopy; out[i++] = fromVal; start++; r = r_1 + 1; } } while ((end - r) > 0 && (med - start) > 0); // copy rest of array if ((end - r) <= 0) { System.arraycopy(in, start, out, i, med - start); } else { System.arraycopy(in, r, out, i, end - r); } } private static int find(byte[] arr, byte val, int bnd, int l, int r, ByteComparator c) { int m = l; int d = 1; while (m <= r) { if (c.compare(val, arr[m]) > bnd) { l = m + 1; } else { r = m - 1; break; } m += d; d <<= 1; } while (l <= r) { m = (l + r) >>> 1; if (c.compare(val, arr[m]) > bnd) { l = m + 1; } else { r = m - 1; } } return l - 1; } private static final CharComparator naturalCharComparison = new CharComparator() { @Override public int compare(char o1, char o2) { return o1 - o2; }}; public static void mergeSort(char[] array, int start, int end) { mergeSort(array, start, end, naturalCharComparison); } public static void mergeSort(char[] array, int start, int end, CharComparator comp) { checkBounds(array.length, start, end); char[] out = Arrays.copyOf(array, array.length); mergeSort(out, array, start, end, comp); } private static void mergeSort(char[] in, char[] out, int start, int end, CharComparator c) { int len = end - start; // use insertion sort for small arrays if (len <= SIMPLE_LENGTH) { for (int i = start + 1; i < end; i++) { char current = out[i]; char prev = out[i - 1]; if (c.compare(prev, current) > 0) { int j = i; do { out[j--] = prev; } while (j > start && (c.compare(prev = out[j - 1], current) > 0)); out[j] = current; } } return; } int med = (end + start) >>> 1; mergeSort(out, in, start, med, c); mergeSort(out, in, med, end, c); // merging // if arrays are already sorted - no merge if (c.compare(in[med - 1], in[med]) <= 0) { System.arraycopy(in, start, out, start, len); return; } int r = med, i = start; // use merging with exponential search do { char fromVal = in[start]; char rVal = in[r]; if (c.compare(fromVal, rVal) <= 0) { int l_1 = find(in, rVal, -1, start + 1, med - 1, c); int toCopy = l_1 - start + 1; System.arraycopy(in, start, out, i, toCopy); i += toCopy; out[i++] = rVal; r++; start = l_1 + 1; } else { int r_1 = find(in, fromVal, 0, r + 1, end - 1, c); int toCopy = r_1 - r + 1; System.arraycopy(in, r, out, i, toCopy); i += toCopy; out[i++] = fromVal; start++; r = r_1 + 1; } } while ((end - r) > 0 && (med - start) > 0); // copy rest of array if ((end - r) <= 0) { System.arraycopy(in, start, out, i, med - start); } else { System.arraycopy(in, r, out, i, end - r); } } private static int find(char[] arr, char val, int bnd, int l, int r, CharComparator c) { int m = l; int d = 1; while (m <= r) { if (c.compare(val, arr[m]) > bnd) { l = m + 1; } else { r = m - 1; break; } m += d; d <<= 1; } while (l <= r) { m = (l + r) >>> 1; if (c.compare(val, arr[m]) > bnd) { l = m + 1; } else { r = m - 1; } } return l - 1; } private static final ShortComparator naturalShortComparison = new ShortComparator() { @Override public int compare(short o1, short o2) { return o1 - o2; }}; public static void mergeSort(short[] array, int start, int end) { mergeSort(array, start, end, naturalShortComparison); } public static void mergeSort(short[] array, int start, int end, ShortComparator comp) { checkBounds(array.length, start, end); short[] out = Arrays.copyOf(array, array.length); mergeSort(out, array, start, end, comp); } private static void mergeSort(short[] in, short[] out, int start, int end, ShortComparator c) { int len = end - start; // use insertion sort for small arrays if (len <= SIMPLE_LENGTH) { for (int i = start + 1; i < end; i++) { short current = out[i]; short prev = out[i - 1]; if (c.compare(prev, current) > 0) { int j = i; do { out[j--] = prev; } while (j > start && (c.compare(prev = out[j - 1], current) > 0)); out[j] = current; } } return; } int med = (end + start) >>> 1; mergeSort(out, in, start, med, c); mergeSort(out, in, med, end, c); // merging // if arrays are already sorted - no merge if (c.compare(in[med - 1], in[med]) <= 0) { System.arraycopy(in, start, out, start, len); return; } int r = med, i = start; // use merging with exponential search do { short fromVal = in[start]; short rVal = in[r]; if (c.compare(fromVal, rVal) <= 0) { int l_1 = find(in, rVal, -1, start + 1, med - 1, c); int toCopy = l_1 - start + 1; System.arraycopy(in, start, out, i, toCopy); i += toCopy; out[i++] = rVal; r++; start = l_1 + 1; } else { int r_1 = find(in, fromVal, 0, r + 1, end - 1, c); int toCopy = r_1 - r + 1; System.arraycopy(in, r, out, i, toCopy); i += toCopy; out[i++] = fromVal; start++; r = r_1 + 1; } } while ((end - r) > 0 && (med - start) > 0); // copy rest of array if ((end - r) <= 0) { System.arraycopy(in, start, out, i, med - start); } else { System.arraycopy(in, r, out, i, end - r); } } private static int find(short[] arr, short val, int bnd, int l, int r, ShortComparator c) { int m = l; int d = 1; while (m <= r) { if (c.compare(val, arr[m]) > bnd) { l = m + 1; } else { r = m - 1; break; } m += d; d <<= 1; } while (l <= r) { m = (l + r) >>> 1; if (c.compare(val, arr[m]) > bnd) { l = m + 1; } else { r = m - 1; } } return l - 1; } private static final IntComparator naturalIntComparison = new IntComparator() { @Override public int compare(int o1, int o2) { return o1 < o2 ? -1 : o1 > o2 ? 1 : 0; }}; public static void mergeSort(int[] array, int start, int end) { mergeSort(array, start, end, naturalIntComparison); } public static void mergeSort(int[] array, int start, int end, IntComparator comp) { checkBounds(array.length, start, end); int[] out = Arrays.copyOf(array, array.length); mergeSort(out, array, start, end, comp); } private static void mergeSort(int[] in, int[] out, int start, int end, IntComparator c) { int len = end - start; // use insertion sort for small arrays if (len <= SIMPLE_LENGTH) { for (int i = start + 1; i < end; i++) { int current = out[i]; int prev = out[i - 1]; if (c.compare(prev, current) > 0) { int j = i; do { out[j--] = prev; } while (j > start && (c.compare(prev = out[j - 1], current) > 0)); out[j] = current; } } return; } int med = (end + start) >>> 1; mergeSort(out, in, start, med, c); mergeSort(out, in, med, end, c); // merging // if arrays are already sorted - no merge if (c.compare(in[med - 1], in[med]) <= 0) { System.arraycopy(in, start, out, start, len); return; } int r = med, i = start; // use merging with exponential search do { int fromVal = in[start]; int rVal = in[r]; if (c.compare(fromVal, rVal) <= 0) { int l_1 = find(in, rVal, -1, start + 1, med - 1, c); int toCopy = l_1 - start + 1; System.arraycopy(in, start, out, i, toCopy); i += toCopy; out[i++] = rVal; r++; start = l_1 + 1; } else { int r_1 = find(in, fromVal, 0, r + 1, end - 1, c); int toCopy = r_1 - r + 1; System.arraycopy(in, r, out, i, toCopy); i += toCopy; out[i++] = fromVal; start++; r = r_1 + 1; } } while ((end - r) > 0 && (med - start) > 0); // copy rest of array if ((end - r) <= 0) { System.arraycopy(in, start, out, i, med - start); } else { System.arraycopy(in, r, out, i, end - r); } } private static int find(int[] arr, int val, int bnd, int l, int r, IntComparator c) { int m = l; int d = 1; while (m <= r) { if (c.compare(val, arr[m]) > bnd) { l = m + 1; } else { r = m - 1; break; } m += d; d <<= 1; } while (l <= r) { m = (l + r) >>> 1; if (c.compare(val, arr[m]) > bnd) { l = m + 1; } else { r = m - 1; } } return l - 1; } private static final LongComparator naturalLongComparison = new LongComparator() { @Override public int compare(long o1, long o2) { return o1 < o2 ? -1 : o1 > o2 ? 1 : 0; }}; public static void mergeSort(long[] array, int start, int end) { mergeSort(array, start, end, naturalLongComparison); } public static void mergeSort(long[] array, int start, int end, LongComparator comp) { checkBounds(array.length, start, end); long[] out = Arrays.copyOf(array, array.length); mergeSort(out, array, start, end, comp); } private static void mergeSort(long[] in, long[] out, int start, int end, LongComparator c) { int len = end - start; // use insertion sort for small arrays if (len <= SIMPLE_LENGTH) { for (int i = start + 1; i < end; i++) { long current = out[i]; long prev = out[i - 1]; if (c.compare(prev, current) > 0) { int j = i; do { out[j--] = prev; } while (j > start && (c.compare(prev = out[j - 1], current) > 0)); out[j] = current; } } return; } int med = (end + start) >>> 1; mergeSort(out, in, start, med, c); mergeSort(out, in, med, end, c); // merging // if arrays are already sorted - no merge if (c.compare(in[med - 1], in[med]) <= 0) { System.arraycopy(in, start, out, start, len); return; } int r = med, i = start; // use merging with exponential search do { long fromVal = in[start]; long rVal = in[r]; if (c.compare(fromVal, rVal) <= 0) { int l_1 = find(in, rVal, -1, start + 1, med - 1, c); int toCopy = l_1 - start + 1; System.arraycopy(in, start, out, i, toCopy); i += toCopy; out[i++] = rVal; r++; start = l_1 + 1; } else { int r_1 = find(in, fromVal, 0, r + 1, end - 1, c); int toCopy = r_1 - r + 1; System.arraycopy(in, r, out, i, toCopy); i += toCopy; out[i++] = fromVal; start++; r = r_1 + 1; } } while ((end - r) > 0 && (med - start) > 0); // copy rest of array if ((end - r) <= 0) { System.arraycopy(in, start, out, i, med - start); } else { System.arraycopy(in, r, out, i, end - r); } } private static int find(long[] arr, long val, int bnd, int l, int r, LongComparator c) { int m = l; int d = 1; while (m <= r) { if (c.compare(val, arr[m]) > bnd) { l = m + 1; } else { r = m - 1; break; } m += d; d <<= 1; } while (l <= r) { m = (l + r) >>> 1; if (c.compare(val, arr[m]) > bnd) { l = m + 1; } else { r = m - 1; } } return l - 1; } private static final FloatComparator naturalFloatComparison = new FloatComparator() { @Override public int compare(float o1, float o2) { return Float.compare(o1, o2); }}; public static void mergeSort(float[] array, int start, int end) { mergeSort(array, start, end, naturalFloatComparison); } public static void mergeSort(float[] array, int start, int end, FloatComparator comp) { checkBounds(array.length, start, end); float[] out = Arrays.copyOf(array, array.length); mergeSort(out, array, start, end, comp); } private static void mergeSort(float[] in, float[] out, int start, int end, FloatComparator c) { int len = end - start; // use insertion sort for small arrays if (len <= SIMPLE_LENGTH) { for (int i = start + 1; i < end; i++) { float current = out[i]; float prev = out[i - 1]; if (c.compare(prev, current) > 0) { int j = i; do { out[j--] = prev; } while (j > start && (c.compare(prev = out[j - 1], current) > 0)); out[j] = current; } } return; } int med = (end + start) >>> 1; mergeSort(out, in, start, med, c); mergeSort(out, in, med, end, c); // merging // if arrays are already sorted - no merge if (c.compare(in[med - 1], in[med]) <= 0) { System.arraycopy(in, start, out, start, len); return; } int r = med, i = start; // use merging with exponential search do { float fromVal = in[start]; float rVal = in[r]; if (c.compare(fromVal, rVal) <= 0) { int l_1 = find(in, rVal, -1, start + 1, med - 1, c); int toCopy = l_1 - start + 1; System.arraycopy(in, start, out, i, toCopy); i += toCopy; out[i++] = rVal; r++; start = l_1 + 1; } else { int r_1 = find(in, fromVal, 0, r + 1, end - 1, c); int toCopy = r_1 - r + 1; System.arraycopy(in, r, out, i, toCopy); i += toCopy; out[i++] = fromVal; start++; r = r_1 + 1; } } while ((end - r) > 0 && (med - start) > 0); // copy rest of array if ((end - r) <= 0) { System.arraycopy(in, start, out, i, med - start); } else { System.arraycopy(in, r, out, i, end - r); } } private static int find(float[] arr, float val, int bnd, int l, int r, FloatComparator c) { int m = l; int d = 1; while (m <= r) { if (c.compare(val, arr[m]) > bnd) { l = m + 1; } else { r = m - 1; break; } m += d; d <<= 1; } while (l <= r) { m = (l + r) >>> 1; if (c.compare(val, arr[m]) > bnd) { l = m + 1; } else { r = m - 1; } } return l - 1; } private static final DoubleComparator naturalDoubleComparison = new DoubleComparator() { @Override public int compare(double o1, double o2) { return Double.compare(o1, o2); }}; public static void mergeSort(double[] array, int start, int end) { mergeSort(array, start, end, naturalDoubleComparison); } public static void mergeSort(double[] array, int start, int end, DoubleComparator comp) { checkBounds(array.length, start, end); double[] out = Arrays.copyOf(array, array.length); mergeSort(out, array, start, end, comp); } private static void mergeSort(double[] in, double[] out, int start, int end, DoubleComparator c) { int len = end - start; // use insertion sort for small arrays if (len <= SIMPLE_LENGTH) { for (int i = start + 1; i < end; i++) { double current = out[i]; double prev = out[i - 1]; if (c.compare(prev, current) > 0) { int j = i; do { out[j--] = prev; } while (j > start && (c.compare(prev = out[j - 1], current) > 0)); out[j] = current; } } return; } int med = (end + start) >>> 1; mergeSort(out, in, start, med, c); mergeSort(out, in, med, end, c); // merging // if arrays are already sorted - no merge if (c.compare(in[med - 1], in[med]) <= 0) { System.arraycopy(in, start, out, start, len); return; } int r = med, i = start; // use merging with exponential search do { double fromVal = in[start]; double rVal = in[r]; if (c.compare(fromVal, rVal) <= 0) { int l_1 = find(in, rVal, -1, start + 1, med - 1, c); int toCopy = l_1 - start + 1; System.arraycopy(in, start, out, i, toCopy); i += toCopy; out[i++] = rVal; r++; start = l_1 + 1; } else { int r_1 = find(in, fromVal, 0, r + 1, end - 1, c); int toCopy = r_1 - r + 1; System.arraycopy(in, r, out, i, toCopy); i += toCopy; out[i++] = fromVal; start++; r = r_1 + 1; } } while ((end - r) > 0 && (med - start) > 0); // copy rest of array if ((end - r) <= 0) { System.arraycopy(in, start, out, i, med - start); } else { System.arraycopy(in, r, out, i, end - r); } } private static int find(double[] arr, double val, int bnd, int l, int r, DoubleComparator c) { int m = l; int d = 1; while (m <= r) { if (c.compare(val, arr[m]) > bnd) { l = m + 1; } else { r = m - 1; break; } m += d; d <<= 1; } while (l <= r) { m = (l + r) >>> 1; if (c.compare(val, arr[m]) > bnd) { l = m + 1; } else { r = m - 1; } } return l - 1; } static void inplace_merge(int first, int middle, int last, IntComparator comp, Swapper swapper) { if (first >= middle || middle >= last) { return; } if (last - first == 2) { if (comp.compare(middle, first) < 0) { swapper.swap(first, middle); } return; } int firstCut; int secondCut; if (middle - first > last - middle) { firstCut = first + (middle - first) / 2; secondCut = lower_bound(middle, last, firstCut, comp); } else { secondCut = middle + (last - middle) / 2; firstCut = upper_bound(first, middle, secondCut, comp); } // rotate(firstCut, middle, secondCut, swapper); // is manually inlined for speed (jitter inlining seems to work only for small call depths, even if methods are "static private") // speedup = 1.7 // begin inline int first2 = firstCut; int middle2 = middle; int last2 = secondCut; if (middle2 != first2 && middle2 != last2) { int first1 = first2; int last1 = middle2; while (first1 < --last1) { swapper.swap(first1++, last1); } first1 = middle2; last1 = last2; while (first1 < --last1) { swapper.swap(first1++, last1); } first1 = first2; last1 = last2; while (first1 < --last1) { swapper.swap(first1++, last1); } } // end inline middle = firstCut + (secondCut - middle); inplace_merge(first, firstCut, middle, comp, swapper); inplace_merge(middle, secondCut, last, comp, swapper); } static int lower_bound(int first, int last, int x, IntComparator comp) { //if (comp==null) throw new NullPointerException(); int len = last - first; while (len > 0) { int half = len / 2; int middle = first + half; if (comp.compare(middle, x) < 0) { first = middle + 1; len -= half + 1; } else { len = half; } } return first; } public static void mergeSort(int fromIndex, int toIndex, IntComparator c, Swapper swapper) { /* We retain the same method signature as quickSort. Given only a comparator and swapper we do not know how to copy and move elements from/to temporary arrays. Hence, in contrast to the JDK mergesorts this is an "in-place" mergesort, i.e. does not allocate any temporary arrays. A non-inplace mergesort would perhaps be faster in most cases, but would require non-intuitive delegate objects... */ int length = toIndex - fromIndex; // Insertion sort on smallest arrays if (length < SMALL) { for (int i = fromIndex; i < toIndex; i++) { for (int j = i; j > fromIndex && (c.compare(j - 1, j) > 0); j--) { swapper.swap(j, j - 1); } } return; } // Recursively sort halves int mid = (fromIndex + toIndex) / 2; mergeSort(fromIndex, mid, c, swapper); mergeSort(mid, toIndex, c, swapper); // If list is already sorted, nothing left to do. This is an // optimization that results in faster sorts for nearly ordered lists. if (c.compare(mid - 1, mid) <= 0) { return; } // Merge sorted halves inplace_merge(fromIndex, mid, toIndex, c, swapper); } static int upper_bound(int first, int last, int x, IntComparator comp) { //if (comp==null) throw new NullPointerException(); int len = last - first; while (len > 0) { int half = len / 2; int middle = first + half; if (comp.compare(x, middle) < 0) { len = half; } else { first = middle + 1; len -= half + 1; } } return first; } }