All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.carrotsearch.hppcrt.sorting.IndirectSort Maven / Gradle / Ivy

Go to download

High Performance Primitive Collections Realtime (fork of HPPC from Carrotsearch) Fundamental data structures (maps, sets, lists, queues, heaps, sorts) generated for combinations of object and primitive types to conserve JVM memory and speed up execution. The Realtime fork intends to extend the existing collections, by tweaking to remove any dynamic allocations at runtime, and to obtain low variance execution times whatever the input nature.

The newest version!
package com.carrotsearch.hppcrt.sorting;

import java.util.Comparator;

/**
 * Sorting routines that return an array of sorted indices implied by a given comparator
 * rather than move elements of whatever the comparator is using for comparisons.
 * 

* A practical use case for this class is when the index of an array is meaningful and one * wants to acquire the order of values in that array. None of the methods in Java * Collections would provide such functionality directly and creating a collection of * boxed {@link Integer} objects for indices seems to be too costly. */ public final class IndirectSort { /** * Minimum window length to apply insertion sort in merge sort. */ private static final int MIN_LENGTH_FOR_INSERTION_SORT = 30; /** * Minimum window length to apply insertion sort in quick sort. */ private static final int MIN_LENGTH_FOR_INSERTION_SORT_IN_QSORT = 17; private static final int DIST_SIZE_DUALQSORT = 13; /** * No instantiation. */ private IndirectSort() { // No instantiation. } /** * Returns the order of elements between indices start and * start + length excluded, as indicated by the given comparator. *

* This routine uses merge sort. It is guaranteed to be stable. * Take note this method generate temporaries. *

*/ public static int[] mergesort(final int start, final int length, final IndirectComparator comparator) { final int[] sorted = new int[length]; IndirectSort.mergesort(start, length, comparator, new int[length], sorted); return sorted; } /** * Returns the order of elements between indices start and * start + length excluded, as indicated by the given comparator. * This method entirely work by using pre-existing arrays, so is fitting for realtime. *

* This routine uses merge sort. It is guaranteed to be stable. *

* @param tmpArray : a temporary array for usage in intermediate computation, its size must be >= length * @param sorted : the sorted indices result. The array must be at least of size length, * and the real validity range is [0; length[ */ public static void mergesort(final int start, final int length, final IndirectComparator comparator, final int[] tmpArray, final int[] sorted) { assert length <= sorted.length; //build an array of indices IndirectSort.fillOrderArray(start, length, tmpArray); System.arraycopy(tmpArray, 0, sorted, 0, length); if (length > 1) { IndirectSort.topDownMergeSort(tmpArray, sorted, 0, length, comparator); } } /** * Returns the order of elements between indices start and * start + length excluded, as indicated by the given comparator. * This method entirely work in-place, so is fitting for realtime. *

* This routine uses Dual-pivot Quicksort, from [Yaroslavskiy 2009], so is NOT stable. *

* @param sorted : the sorted indices result. The array must be at least of size length, * and the real validity range is [0; length[ */ public static void quicksort(final int start, final int length, final IndirectComparator comparator, final int[] sorted) { assert length <= sorted.length; //build an array of indices IndirectSort.fillOrderArray(start, length, sorted); if (length > 1) { IndirectSort.dualPivotQuicksort(sorted, start, start + length - 1, comparator); } } /** * Returns the order of elements between indices start and * length + start excluded, as indicated by the given comparator. This method * is equivalent to calling {@link #mergesort(int, int, IndirectComparator)} with * {@link IndirectComparator.DelegatingComparator}. *

* This routine uses merge sort. It is guaranteed to be stable. *

* Take note this method generate temporaries. */ public static int[] mergesort(final T[] input, final int start, final int length, final Comparator comparator) { return IndirectSort.mergesort(start, length, new IndirectComparator.DelegatingComparator( input, comparator)); } /** * Perform a recursive, descending merge sort. * * @param fromIndex inclusive * @param toIndex exclusive */ private static void topDownMergeSort(final int[] src, final int[] dst, final int fromIndex, final int toIndex, final IndirectComparator comp) { if (toIndex - fromIndex <= IndirectSort.MIN_LENGTH_FOR_INSERTION_SORT) { IndirectSort.insertionSort(fromIndex, toIndex - fromIndex, dst, comp); return; } final int mid = (fromIndex + toIndex) >>> 1; IndirectSort.topDownMergeSort(dst, src, fromIndex, mid, comp); IndirectSort.topDownMergeSort(dst, src, mid, toIndex, comp); /* * Both splits in of src are now sorted. */ if (comp.compare(src[mid - 1], src[mid]) <= 0) { /* * If the lowest element in upper slice is larger than the highest element in * the lower slice, simply copy over, the data is fully sorted. */ System.arraycopy(src, fromIndex, dst, fromIndex, toIndex - fromIndex); } else { /* * Run a manual merge. */ for (int i = fromIndex, j = mid, k = fromIndex; k < toIndex; k++) { if (j == toIndex || (i < mid && comp.compare(src[i], src[j]) <= 0)) { dst[k] = src[i++]; } else { dst[k] = src[j++]; } } } } /** * Internal insertion sort for ints. */ private static void insertionSort(final int off, final int len, final int[] order, final IndirectComparator intComparator) { int v, j, t; for (int i = off + 1; i < off + len; i++) { v = order[i]; j = i; while (j > off && intComparator.compare(t = order[j - 1], v) > 0) { order[j--] = t; } order[j] = v; } } /** * Fill an existing array to build an order array. * @param start * @param order */ private static void fillOrderArray(final int start, final int length, final int[] order) { for (int i = 0; i < length; i++) { order[i] = start + i; } } /** * Dual-pivot Quicksort, from [Yaroslavskiy 2009] paper * applied on the indirectSort * @param a * @param left * @param right */ private static void dualPivotQuicksort(final int[] a, final int left, final int right, final IndirectComparator comp) { final int len = right - left; int x; //insertion sort //to prevent too-big recursion, swap to insertion sort below a certain size if (len <= IndirectSort.MIN_LENGTH_FOR_INSERTION_SORT_IN_QSORT) { IndirectSort.insertionSort(left, len + 1, a, comp); return; } // median indexes final int sixth = len / 6; final int m1 = left + sixth; final int m2 = m1 + sixth; final int m3 = m2 + sixth; final int m4 = m3 + sixth; final int m5 = m4 + sixth; // 5-element sorting network if (comp.compare(a[m1], a[m2]) > 0 /* a[m1] > a[m2]*/) { x = a[m1]; a[m1] = a[m2]; a[m2] = x; } if (comp.compare(a[m4], a[m5]) > 0 /* a[m4] > a[m5]*/) { x = a[m4]; a[m4] = a[m5]; a[m5] = x; } if (comp.compare(a[m1], a[m3]) > 0 /*a[m1] > a[m3]*/) { x = a[m1]; a[m1] = a[m3]; a[m3] = x; } if (comp.compare(a[m2], a[m3]) > 0 /* a[m2] > a[m3]*/) { x = a[m2]; a[m2] = a[m3]; a[m3] = x; } if (comp.compare(a[m1], a[m4]) > 0 /* a[m1] > a[m4]*/) { x = a[m1]; a[m1] = a[m4]; a[m4] = x; } if (comp.compare(a[m3], a[m4]) > 0 /*a[m3] > a[m4]*/) { x = a[m3]; a[m3] = a[m4]; a[m4] = x; } if (comp.compare(a[m2], a[m5]) > 0 /* a[m2] > a[m5]*/) { x = a[m2]; a[m2] = a[m5]; a[m5] = x; } if (comp.compare(a[m2], a[m3]) > 0 /*a[m2] > a[m3]*/) { x = a[m2]; a[m2] = a[m3]; a[m3] = x; } if (comp.compare(a[m4], a[m5]) > 0 /* a[m4] > a[m5]*/) { x = a[m4]; a[m4] = a[m5]; a[m5] = x; } // pivots: [ < pivot1 | pivot1 <= && <= pivot2 | > pivot2 ] final int pivot1 = a[m2]; final int pivot2 = a[m4]; final boolean diffPivots = comp.compare(pivot1, pivot2) != 0; a[m2] = a[left]; a[m4] = a[right]; // center part pointers int less = left + 1; int great = right - 1; // sorting if (diffPivots) { for (int k = less; k <= great; k++) { x = a[k]; if (comp.compare(x, pivot1) < 0/* x < pivot1 */) { a[k] = a[less]; a[less++] = x; } else if (comp.compare(x, pivot2) > 0 /* x > pivot2 */) { while (comp.compare(a[great], pivot2) > 0 /* a[great] > pivot2 */&& k < great) { great--; } a[k] = a[great]; a[great--] = x; x = a[k]; if (comp.compare(x, pivot1) < 0 /*x < pivot1*/) { a[k] = a[less]; a[less++] = x; } } } } else { for (int k = less; k <= great; k++) { x = a[k]; if (comp.compare(x, pivot1) == 0 /*x == pivot1*/) { continue; } if (comp.compare(x, pivot1) < 0 /* x < pivot1 */) { a[k] = a[less]; a[less++] = x; } else { while (comp.compare(a[great], pivot2) > 0 /* a[great] > pivot2*/&& k < great) { great--; } a[k] = a[great]; a[great--] = x; x = a[k]; if (comp.compare(x, pivot1) < 0 /*x < pivot1*/) { a[k] = a[less]; a[less++] = x; } } } } // swap a[left] = a[less - 1]; a[less - 1] = pivot1; a[right] = a[great + 1]; a[great + 1] = pivot2; // left and right parts IndirectSort.dualPivotQuicksort(a, left, less - 2, comp); IndirectSort.dualPivotQuicksort(a, great + 2, right, comp); // equal elements if (great - less > len - IndirectSort.DIST_SIZE_DUALQSORT && diffPivots) { for (int k = less; k <= great; k++) { x = a[k]; if (comp.compare(x, pivot1) == 0 /*x == pivot1*/) { a[k] = a[less]; a[less++] = x; } else if (comp.compare(x, pivot2) == 0 /*x == pivot2*/) { a[k] = a[great]; a[great--] = x; x = a[k]; if (comp.compare(x, pivot1) == 0 /*x == pivot1*/) { a[k] = a[less]; a[less++] = x; } } } } // center part if (diffPivots) { IndirectSort.dualPivotQuicksort(a, less, great, comp); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy