diff --git a/projects/samskivert/src/java/com/samskivert/util/QuickSort.java b/projects/samskivert/src/java/com/samskivert/util/QuickSort.java new file mode 100644 index 00000000..42bda1af --- /dev/null +++ b/projects/samskivert/src/java/com/samskivert/util/QuickSort.java @@ -0,0 +1,329 @@ +// +// $Id: QuickSort.java,v 1.1 2002/02/19 03:37:31 mdb Exp $ +// +// samskivert library - useful routines for java programs +// Copyright (C) 2001 Michael Bayne +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.samskivert.util; + +import java.util.Comparator; + +/** + * A class to sort arrays of objects (quickly even) + */ +public class QuickSort +{ + /** + * Sorts the supplied array of objects from least to greatest, using + * the supplied comparator. + */ + public static void sort (Object[] a, Comparator comp) + { + csort(a, 0, a.length - 1, comp); + } + + /** + * Sorts the supplied array of comparable objects from least to + * greatest. + */ + public static void sort (Comparable[] a) + { + sort(a, 0, a.length - 1); + } + + /** + * Sorts the supplied array of objects from greatest to least, using + * the supplied comparator. + */ + public static void rsort (Object[] a, Comparator comp) + { + crsort(a, 0, a.length - 1, comp); + } + + /** + * Sorts the supplied array of comparable objects from greatest to + * least. + */ + public static void rsort (Comparable[] a) + { + rsort(a, 0, a.length - 1); + } + + /** + * Sorts the specified subset of the supplied array from least to + * greatest, using the supplied comparator. + * + * @param a the array of objects to be sorted. + * @param lo0 the index of the lowest element to be included in the + * sort. + * @param hi0 the index of the highest element to be included in the + * sort. + * @param comp the comparator to use to establish ordering between + * elements. + */ + public static void csort (Object[] a, int lo0, int hi0, Comparator comp) + { + // bail out if we're already done + if (hi0 <= lo0) { + return; + } + + Object t; + + // if this is a two element file, do a simple sort on it + 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) { + csort(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) { + csort(a, hi+1, hi0, comp); + } + } + + /** + * Sorts the specified subset of the supplied array from greatest to + * least, using the supplied comparator. + * + * @param a the array of objects to be sorted. + * @param lo0 the index of the lowest element to be included in the + * sort. + * @param hi0 the index of the highest element to be included in the + * sort. + * @param comp the comparator to use to establish ordering between + * elements. + */ + public static void crsort (Object[] a, int lo0, int hi0, Comparator comp) + { + // bail out if we're already done + if (hi0 <= lo0) { + return; + } + + Object t; + + // if this is a two element file, do a simple sort on it + if (hi0 - lo0 == 1) { + // if they're not already sorted, swap them + if (comp.compare(a[lo0], a[hi0]) < 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(mid, a[++lo]) < 0); + + // find an element that is smaller than or equal to + // the partition element starting from the right Index. + while (comp.compare(a[--hi], mid) < 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) { + crsort(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) { + crsort(a, hi+1, hi0, comp); + } + } + + /** + * Sorts the specified subset of the supplied array of comparables + * from least to greatest, using the supplied comparator. + * + * @param a the array of objects to be sorted. + * @param lo0 the index of the lowest element to be included in the + * sort. + * @param hi0 the index of the highest element to be included in the + * sort. + */ + public static void sort (Comparable[] a, int lo0, int hi0) + { + // bail out if we're already done + if (hi0 <= lo0) { + return; + } + + Comparable t; + + // if this is a two element file, do a simple sort on it + if (hi0 - lo0 == 1) { + // if they're not already sorted, swap them + if (a[lo0].compareTo(a[hi0]) > 0) { + t = a[lo0]; a[lo0] = a[hi0]; a[hi0] = t; + } + return; + } + + // the middle element in the array is our partitioning element + Comparable 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 (mid.compareTo(a[++lo]) > 0); + + // find an element that is smaller than or equal to + // the partition element starting from the right Index. + while (mid.compareTo(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) { + sort(a, lo0, lo-1); + } + + // if the left index has not reached the right side of array + // must now sort the right partition + if (hi+1 < hi0) { + sort(a, hi+1, hi0); + } + } + + /** + * Sorts the specified subset of the supplied array of comparables + * from greatest to least, using the supplied comparator. + * + * @param a the array of objects to be sorted. + * @param lo0 the index of the lowest element to be included in the + * sort. + * @param hi0 the index of the highest element to be included in the + * sort. + */ + public static void rsort (Comparable[] a, int lo0, int hi0) + { + // bail out if we're already done + if (hi0 <= lo0) { + return; + } + + Comparable t; + + // if this is a two element file, do a simple sort on it + if (hi0 - lo0 == 1) { + // if they're not already sorted, swap them + if (a[lo0].compareTo(a[hi0]) < 0) { + t = a[lo0]; a[lo0] = a[hi0]; a[hi0] = t; + } + return; + } + + // the middle element in the array is our partitioning element + Comparable 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 (mid.compareTo(a[++lo]) < 0); + + // find an element that is smaller than or equal to + // the partition element starting from the right Index. + while (mid.compareTo(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) { + rsort(a, lo0, lo-1); + } + + // if the left index has not reached the right side of array + // must now sort the right partition + if (hi+1 < hi0) { + rsort(a, hi+1, hi0); + } + } +} diff --git a/projects/samskivert/tests/src/java/com/samskivert/util/QuickSortTest.java b/projects/samskivert/tests/src/java/com/samskivert/util/QuickSortTest.java new file mode 100644 index 00000000..d3d9b9be --- /dev/null +++ b/projects/samskivert/tests/src/java/com/samskivert/util/QuickSortTest.java @@ -0,0 +1,102 @@ +// +// $Id: QuickSortTest.java,v 1.1 2002/02/19 03:37:32 mdb Exp $ + +package com.samskivert.util; + +import java.util.Comparator; + +import junit.framework.Test; +import junit.framework.TestCase; + +/** + * Tests the {@link QuickSort} class. + */ +public class QuickSortTest extends TestCase +{ + public QuickSortTest () + { + super(QuickSortTest.class.getName()); + } + + public void runTest () + { + Integer[] a = new Integer[100]; + + Comparator comp = new Comparator() { + public int compare (Object x, Object y) { + return ((Integer)x).intValue() - ((Integer)y).intValue(); + } + }; + + for (int d = 1; d <= 100; d++) { + for (int n = 0; n < 100; n++) { + a[n] = new Integer(n / d); + QuickSort.csort (a, 0, n, comp); + for (int i = 0; i <= n; i++) { + assert("Failure for up " + n + "/" + d, + a[i].intValue() == i / d); + } + } + } + // System.out.println("up test ok"); + + for (int d = 1; d <= 100; d++) { + for (int n = 0; n < 100; n++) { + for (int i = 0; i <= n; i++) { + a[i] = new Integer((n - i) / d); + } + QuickSort.csort (a, 0, n, comp); + for (int i = 0; i <= n; i++) { + assert("Failure for down " + n + "/" + d, + a[i].intValue() == i / d); + } + } + } + // System.out.println("down test ok"); + + int tests = 1000; + for (int sorts = 0; sorts < tests; sorts++) { + int n = rand(100); + for (int i = 0; i <= n; i++) { + a[i] = new Integer(rand(30000)); + } + + QuickSort.csort (a, 0, n, comp); + for (int i = 0; i < n; i++) { + assert("Failure for random " + n, + a[i].intValue() <= a[i+1].intValue()); + } + + QuickSort.csort (a, 0, n, comp); + for (int i = 0; i < n; i++) { + assert("Failure for random " + n + " (resort)", + a[i].intValue() <= a[i+1].intValue()); + } + + a[rand(n+1)] = new Integer(rand(30000)); + QuickSort.csort (a, 0, n, comp); + for (int i = 0; i < n; i++) { + assert("Failure for random " + n + " (resort 2)", + a[i].intValue() <= a[i+1].intValue()); + } + } + // System.out.println("successfully sorted " + tests + + // " random arrays"); + } + + public static Test suite () + { + return new QuickSortTest(); + } + + public static void main (String[] args) + { + QuickSortTest test = new QuickSortTest(); + test.runTest(); + } + + private static int rand (int n) + { + return (int)(Math.random() * n); + } +}