/* * Copyright (c) 2009-2012 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of 'jMonkeyEngine' nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.jme3.util; import java.util.Arrays; import java.util.Comparator; /** * Quick and merge sort implementations that create no garbage, unlike {@link * Arrays#sort}. The merge sort is stable, the quick sort is not. */ public class SortUtil { /** * The size at or below which we will use insertion sort because it's * probably faster. */ private static final int INSERTION_SORT_THRESHOLD = 7; /** procedure optimizedGnomeSort(a[]) pos := 1 last := 0 while pos < length(a) if (a[pos] >= a[pos-1]) if (last != 0) pos := last last := 0 end if pos := pos + 1 else swap a[pos] and a[pos-1] if (pos > 1) if (last == 0) last := pos end if pos := pos - 1 else pos := pos + 1 end if end if end while end procedure */ public static void gsort(Object[] a, Comparator comp) { int pos = 1; int last = 0; int length = a.length; while (pos < length){ if ( comp.compare(a[pos], a[pos-1]) >= 0 ){ if (last != 0){ pos = last; last = 0; } pos ++; }else{ Object tmp = a[pos]; a[pos] = a[pos-1]; a[pos-1] = tmp; if (pos > 1){ if (last == 0){ last = pos; } pos --; }else{ pos ++; } } } // int p = 0; // int l = a.length; // while (p < l) { // int pm1 = p - 1; // if (p == 0 || comp.compare(a[p], a[pm1]) >= 0) { // p++; // } else { // Object t = a[p]; // a[p] = a[pm1]; // a[pm1] = t; // p--; // } // } } private static void test(Float[] original, Float[] sorted, Comparator<Float> ic) { long time, dt; time = System.nanoTime(); for (int i = 0; i < 1000000; i++) { System.arraycopy(original, 0, sorted, 0, original.length); gsort(sorted, ic); } dt = System.nanoTime() - time; System.out.println("GSort " + (dt/1000000.0) + " ms"); time = System.nanoTime(); for (int i = 0; i < 1000000; i++) { System.arraycopy(original, 0, sorted, 0, original.length); qsort(sorted, ic); } dt = System.nanoTime() - time; System.out.println("QSort " + (dt/1000000.0) + " ms"); time = System.nanoTime(); for (int i = 0; i < 1000000; i++) { System.arraycopy(original, 0, sorted, 0, original.length); msort(original, sorted, ic); } dt = System.nanoTime() - time; System.out.println("MSort " + (dt/1000000.0) + " ms"); time = System.nanoTime(); for (int i = 0; i < 1000000; i++) { System.arraycopy(original, 0, sorted, 0, original.length); Arrays.sort(sorted, ic); } dt = System.nanoTime() - time; System.out.println("ASort " + (dt/1000000.0) + " ms"); } public static void main(String[] args) { Comparator<Float> ic = new Comparator<Float>() { public int compare(Float o1, Float o2) { return (int) (o1 - o2); } }; Float[] original = new Float[]{2f, 1f, 5f, 3f, 4f, 6f, 8f, 9f, 11f, 10f, 12f, 13f, 14f, 15f, 7f, 19f, 20f, 18f, 16f, 17f, 21f, 23f, 22f, 24f, 25f, 27f, 26f, 29f, 28f, 30f, 31f}; Float[] sorted = new Float[original.length]; while (true) { test(original, sorted, ic); } } /** * Quick sorts the supplied array using the specified comparator. */ public static void qsort(Object[] a, Comparator comp) { qsort(a, 0, a.length - 1, comp); } /** * Quick sorts the supplied array using the specified comparator. * * @param lo0 the index of the lowest element to include in the sort. * @param hi0 the index of the highest element to include in the sort. */ @SuppressWarnings("unchecked") public static void qsort(Object[] a, int lo0, int hi0, Comparator comp) { // bail out if we're already done if (hi0 <= lo0) { return; } // if this is a two element list, do a simple sort on it Object t; if (hi0 - lo0 == 1) { // if they're not already sorted, swap them if (comp.compare(a[hi0], a[lo0]) < 0) { t = a[lo0]; a[lo0] = a[hi0]; a[hi0] = t; } return; } // the middle element in the array is our partitioning element Object mid = a[(lo0 + hi0) / 2]; // set up our partitioning boundaries int lo = lo0 - 1, hi = hi0 + 1; // loop through the array until indices cross for (;;) { // find the first element that is greater than or equal to // the partition element starting from the left Index. while (comp.compare(a[++lo], mid) < 0); // find an element that is smaller than or equal to // the partition element starting from the right Index. while (comp.compare(mid, a[--hi]) < 0); // swap the two elements or bail out of the loop if (hi > lo) { t = a[lo]; a[lo] = a[hi]; a[hi] = t; } else { break; } } // if the right index has not reached the left side of array // must now sort the left partition if (lo0 < lo - 1) { qsort(a, lo0, lo - 1, comp); } // if the left index has not reached the right side of array // must now sort the right partition if (hi + 1 < hi0) { qsort(a, hi + 1, hi0, comp); } } public static void qsort(int[] a, int lo0, int hi0, Comparator comp) { // bail out if we're already done if (hi0 <= lo0) { return; } // if this is a two element list, do a simple sort on it int t; if (hi0 - lo0 == 1) { // if they're not already sorted, swap them if (comp.compare(a[hi0], a[lo0]) < 0) { t = a[lo0]; a[lo0] = a[hi0]; a[hi0] = t; } return; } // the middle element in the array is our partitioning element int mid = a[(lo0 + hi0) / 2]; // set up our partitioning boundaries int lo = lo0 - 1, hi = hi0 + 1; // loop through the array until indices cross for (;;) { // find the first element that is greater than or equal to // the partition element starting from the left Index. while (comp.compare(a[++lo], mid) < 0); // find an element that is smaller than or equal to // the partition element starting from the right Index. while (comp.compare(mid, a[--hi]) < 0); // swap the two elements or bail out of the loop if (hi > lo) { t = a[lo]; a[lo] = a[hi]; a[hi] = t; } else { break; } } // if the right index has not reached the left side of array // must now sort the left partition if (lo0 < lo - 1) { qsort(a, lo0, lo - 1, comp); } // if the left index has not reached the right side of array // must now sort the right partition if (hi + 1 < hi0) { qsort(a, hi + 1, hi0, comp); } } /** * Merge sort */ public static void msort(Object[] src, Object[] dest, Comparator comp){ msort(src, dest, 0, src.length - 1, comp); } /** * Merge sort * * @param src Source array * @param dest Destination array * @param low Index of beginning element * @param high Index of end element * @param comp Comparator */ public static void msort(Object[] src, Object[] dest, int low, int high, Comparator comp) { if(low < high) { int center = (low + high) / 2; msort(src, dest, low, center, comp); msort(src, dest, center + 1, high, comp); merge(src, dest, low, center + 1, high, comp); } } private static void merge(Object[] src, Object[] dest, int low, int middle, int high, Comparator comp) { int leftEnd = middle - 1; int pos = low; int numElements = high - low + 1; while (low <= leftEnd && middle <= high) { if (comp.compare(src[low], src[middle]) <= 0) { dest[pos++] = src[low++]; } else { dest[pos++] = src[middle++]; } } while (low <= leftEnd) { dest[pos++] = src[low++]; } while (middle <= high) { dest[pos++] = src[middle++]; } for (int i = 0; i < numElements; i++, high--) { src[high] = dest[high]; } } }