Sort.java Source code

Java tutorial

Introduction

Here is the source code for Sort.java

Source

// HTMLParser Library - A java-based parser for HTML
// http://htmlparser.org
// Copyright (C) 2006 Derrick Oswald
//
// Revision Control Information
//
// $URL: https://svn.sourceforge.net/svnroot/htmlparser/trunk/lexer/src/main/java/org/htmlparser/util/sort/Sort.java $
// $Author: derrickoswald $
// $Date: 2006-09-16 10:44:17 -0400 (Sat, 16 Sep 2006) $
// $Revision: 4 $
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Common Public License; either
// version 1.0 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
// Common Public License for more details.
//
// You should have received a copy of the Common Public License
// along with this library; if not, the license is available from
// the Open Source Initiative (OSI) website:
//   http://opensource.org/licenses/cpl1.0.php

//package org.htmlparser.util.sort;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

/**
 * A quick sort algorithm to sort Vectors or arrays. Provides sort and binary
 * search capabilities.
 * <p>
 * This all goes away in JDK 1.2.
 * <p>
 * 
 * @author James Gosling
 * @author Kevin A. Smith
 * @author Derrick Oswald
 * @version 1.4, 11 June, 1997
 */
public class Sort {
    /**
     * No object of this class need ever be instantiated. All methods are
     * static.
     */
    private Sort() {
    }

    /**
     * This is a generic version of C.A.R Hoare's Quick Sort algorithm. This
     * will handle vectors that are already sorted, and vectors with duplicate
     * keys. Equivalent to:
     * 
     * <pre>
     * QuickSort(v, 0, v.size() - 1);
     * </pre>
     * 
     * @param v
     *            A <code>Vector</code> of <code>Ordered</code> items.
     * @exception ClassCastException
     *                If the vector contains objects that are not
     *                <code>Ordered</code>.
     */
    public static void QuickSort(Vector v) throws ClassCastException {
        QuickSort(v, 0, v.size() - 1);
    }

    /**
     * This is a generic version of C.A.R Hoare's Quick Sort algorithm. This
     * will handle vectors that are already sorted, and vectors with duplicate
     * keys.
     * <p>
     * If you think of a one dimensional vector as going from the lowest index
     * on the left to the highest index on the right then the parameters to this
     * function are lowest index or left and highest index or right.
     * 
     * @param v
     *            A <code>Vector</code> of <code>Ordered</code> items.
     * @param lo0
     *            Left boundary of vector partition.
     * @param hi0
     *            Right boundary of vector partition.
     * @exception ClassCastException
     *                If the vector contains objects that are not
     *                <code>Ordered</code>.
     */
    public static void QuickSort(Vector v, int lo0, int hi0) throws ClassCastException {
        int lo = lo0;
        int hi = hi0;
        Ordered mid;

        if (hi0 > lo0) { // arbitrarily establish partition element as the
                         // midpoint of the vector
            mid = (Ordered) v.elementAt((lo0 + hi0) / 2);

            // loop through the vector until indices cross
            while (lo <= hi) {
                // find the first element that is greater than or equal to
                // the partition element starting from the left index
                while ((lo < hi0) && (0 > ((Ordered) v.elementAt(lo)).compare(mid)))
                    ++lo;

                // find an element that is smaller than or equal to
                // the partition element starting from the right index
                while ((hi > lo0) && (0 < ((Ordered) v.elementAt(hi)).compare(mid)))
                    --hi;

                // if the indexes have not crossed, swap
                if (lo <= hi)
                    swap(v, lo++, hi--);
            }

            // if the right index has not reached the left side of array
            // must now sort the left partition
            if (lo0 < hi)
                QuickSort(v, lo0, hi);

            // if the left index has not reached the right side of array
            // must now sort the right partition
            if (lo < hi0)
                QuickSort(v, lo, hi0);
        }
    }

    private static void swap(Vector v, int i, int j) {
        Object o;

        o = v.elementAt(i);
        v.setElementAt(v.elementAt(j), i);
        v.setElementAt(o, j);
    }

    /**
     * This is a generic version of C.A.R Hoare's Quick Sort algorithm. This
     * will handle arrays that are already sorted, and arrays with duplicate
     * keys.
     * <p>
     * Equivalent to:
     * 
     * <pre>
     * QuickSort(a, 0, a.length - 1);
     * </pre>
     * 
     * @param a
     *            An array of <code>Ordered</code> items.
     */
    public static void QuickSort(Ordered[] a) {
        QuickSort(a, 0, a.length - 1);
    }

    /**
     * This is a generic version of C.A.R Hoare's Quick Sort algorithm. This
     * will handle arrays that are already sorted, and arrays with duplicate
     * keys.
     * <p>
     * If you think of a one dimensional array as going from the lowest index on
     * the left to the highest index on the right then the parameters to this
     * function are lowest index or left and highest index or right.
     * 
     * @param a
     *            An array of <code>Ordered</code> items.
     * @param lo0
     *            Left boundary of array partition.
     * @param hi0
     *            Right boundary of array partition.
     */
    public static void QuickSort(Ordered[] a, int lo0, int hi0) {
        int lo = lo0;
        int hi = hi0;
        Ordered mid;

        if (hi0 > lo0) {
            // arbitrarily establish partition element as the midpoint of the
            // array
            mid = a[(lo0 + hi0) / 2];

            // loop through the vector until indices cross
            while (lo <= hi) {
                // find the first element that is greater than or equal to
                // the partition element starting from the left index
                while ((lo < hi0) && (0 > a[lo].compare(mid)))
                    ++lo;

                // find an element that is smaller than or equal to
                // the partition element starting from the right Index.
                while ((hi > lo0) && (0 < a[hi].compare(mid)))
                    --hi;

                // if the indexes have not crossed, swap
                if (lo <= hi)
                    swap(a, lo++, hi--);
            }

            // if the right index has not reached the left side of array
            // must now sort the left partition
            if (lo0 < hi)
                QuickSort(a, lo0, hi);

            // if the left index has not reached the right side of array
            // must now sort the right partition
            if (lo < hi0)
                QuickSort(a, lo, hi0);
        }
    }

    /**
     * Swaps two elements of an array.
     * 
     * @param a
     *            The array of elements.
     * @param i
     *            The index of one item to swap.
     * @param j
     *            The index of the other item to swap.
     */
    private static void swap(Object[] a, int i, int j) {
        Object o;
        o = a[i];
        a[i] = a[j];
        a[j] = o;
    }

    /**
     * This is a string version of C.A.R Hoare's Quick Sort algorithm. This will
     * handle arrays that are already sorted, and arrays with duplicate keys.
     * <p>
     * Equivalent to:
     * 
     * <pre>
     * QuickSort(a, 0, a.length - 1);
     * </pre>
     * 
     * @param a
     *            An array of <code>String</code> items.
     */
    public static void QuickSort(String[] a) {
        QuickSort(a, 0, a.length - 1);
    }

    /**
     * This is a string version of C.A.R Hoare's Quick Sort algorithm. This will
     * handle arrays that are already sorted, and arrays with duplicate keys.
     * <p>
     * If you think of a one dimensional array as going from the lowest index on
     * the left to the highest index on the right then the parameters to this
     * function are lowest index or left and highest index or right.
     * 
     * @param a
     *            An array of <code>String</code> items.
     * @param lo0
     *            Left boundary of array partition.
     * @param hi0
     *            Right boundary of array partition.
     */
    public static void QuickSort(String[] a, int lo0, int hi0) {
        int lo = lo0;
        int hi = hi0;
        String mid;

        if (hi0 > lo0) {
            // arbitrarily establish partition element as the midpoint of the
            // array
            mid = a[(lo0 + hi0) / 2];

            // loop through the vector until indices cross
            while (lo <= hi) {
                // find the first element that is greater than or equal to
                // the partition element starting from the left index
                while ((lo < hi0) && (0 > a[lo].compareTo(mid)))
                    ++lo;

                // find an element that is smaller than or equal to
                // the partition element starting from the right Index.
                while ((hi > lo0) && (0 < a[hi].compareTo(mid)))
                    --hi;

                // if the indexes have not crossed, swap
                if (lo <= hi)
                    swap(a, lo++, hi--);
            }

            // if the right index has not reached the left side of array
            // must now sort the left partition
            if (lo0 < hi)
                QuickSort(a, lo0, hi);

            // if the left index has not reached the right side of array
            // must now sort the right partition
            if (lo < hi0)
                QuickSort(a, lo, hi0);
        }
    }

    /**
     * This is a generic version of C.A.R Hoare's Quick Sort algorithm. This
     * will handle Sortable objects that are already sorted, and Sortable
     * objects with duplicate keys.
     * <p>
     * 
     * @param sortable
     *            A <code>Sortable</code> object.
     * @param lo0
     *            Left boundary of partition.
     * @param hi0
     *            Right boundary of partition.
     */
    public static void QuickSort(Sortable sortable, int lo0, int hi0) {
        int lo = lo0;
        int hi = hi0;
        Ordered mid;
        Ordered test;

        if (hi0 > lo0) { // arbitrarily establish partition element as the
                         // midpoint of the vector
            mid = sortable.fetch((lo0 + hi0) / 2, null);
            test = null;

            // loop through the vector until indices cross
            while (lo <= hi) {
                // find the first element that is greater than or equal to
                // the partition element starting from the left index
                while ((lo < hi0) && (0 > (test = sortable.fetch(lo, test)).compare(mid)))
                    ++lo;

                // find an element that is smaller than or equal to
                // the partition element starting from the right index
                while ((hi > lo0) && (0 < (test = sortable.fetch(hi, test)).compare(mid)))
                    --hi;

                // if the indexes have not crossed, swap
                if (lo <= hi)
                    sortable.swap(lo++, hi--);
            }

            // if the right index has not reached the left side of array
            // must now sort the left partition
            if (lo0 < hi)
                QuickSort(sortable, lo0, hi);

            // if the left index has not reached the right side of array
            // must now sort the right partition
            if (lo < hi0)
                QuickSort(sortable, lo, hi0);
        }
    }

    /**
     * This is a generic version of C.A.R Hoare's Quick Sort algorithm. This
     * will handle Sortable objects that are already sorted, and Sortable
     * objects with duplicate keys.
     * <p>
     * Equivalent to:
     * 
     * <pre>
     * QuickSort(sortable, sortable.first(), sortable.last());
     * </pre>
     * 
     * @param sortable
     *            A <code>Sortable</code> object.
     */
    public static void QuickSort(Sortable sortable) {
        QuickSort(sortable, sortable.first(), sortable.last());
    }

    /**
     * Sort a Hashtable.
     * 
     * @param h
     *            A Hashtable with String or Ordered keys.
     * @return A sorted array of the keys.
     * @exception ClassCastException
     *                If the keys of the hashtable are not <code>Ordered</code>.
     */
    public static Object[] QuickSort(Hashtable h) throws ClassCastException {
        Enumeration e;
        boolean are_strings;
        Object[] ret;

        // make the array
        ret = new Ordered[h.size()];
        e = h.keys();
        are_strings = true; // until proven otherwise
        for (int i = 0; i < ret.length; i++) {
            ret[i] = e.nextElement();
            if (are_strings && !(ret[i] instanceof String))
                are_strings = false;
        }

        // sort it
        if (are_strings)
            QuickSort((String[]) ret);
        else
            QuickSort((Ordered[]) ret);

        return (ret);
    }

    /**
     * Binary search for an object
     * 
     * @param set
     *            The collection of <code>Ordered</code> objects.
     * @param ref
     *            The name to search for.
     * @param lo
     *            The lower index within which to look.
     * @param hi
     *            The upper index within which to look.
     * @return The index at which reference was found or is to be inserted.
     */
    public static int bsearch(Sortable set, Ordered ref, int lo, int hi) {
        int num;
        int mid;
        Ordered ordered;
        int half;
        int result;
        int ret;

        ret = -1;

        num = (hi - lo) + 1;
        ordered = null;
        while ((-1 == ret) && (lo <= hi)) {
            half = num / 2;
            mid = lo + ((0 != (num & 1)) ? half : half - 1);
            ordered = set.fetch(mid, ordered);
            result = ref.compare(ordered);
            if (0 == result)
                ret = mid;
            else if (0 > result) {
                hi = mid - 1;
                num = ((0 != (num & 1)) ? half : half - 1);
            } else {
                lo = mid + 1;
                num = half;
            }
        }
        if (-1 == ret)
            ret = lo;

        return (ret);
    }

    /**
     * Binary search for an object
     * 
     * @param set
     *            The collection of <code>Ordered</code> objects.
     * @param ref
     *            The name to search for.
     * @return The index at which reference was found or is to be inserted.
     */
    public static int bsearch(Sortable set, Ordered ref) {
        return (bsearch(set, ref, set.first(), set.last()));
    }

    /**
     * Binary search for an object
     * 
     * @param vector
     *            The vector of <code>Ordered</code> objects.
     * @param ref
     *            The name to search for.
     * @param lo
     *            The lower index within which to look.
     * @param hi
     *            The upper index within which to look.
     * @return The index at which reference was found or is to be inserted.
     */
    public static int bsearch(Vector vector, Ordered ref, int lo, int hi) {
        int num;
        int mid;
        int half;
        int result;
        int ret;

        ret = -1;

        num = (hi - lo) + 1;
        while ((-1 == ret) && (lo <= hi)) {
            half = num / 2;
            mid = lo + ((0 != (num & 1)) ? half : half - 1);
            result = ref.compare(vector.elementAt(mid));
            if (0 == result)
                ret = mid;
            else if (0 > result) {
                hi = mid - 1;
                num = ((0 != (num & 1)) ? half : half - 1);
            } else {
                lo = mid + 1;
                num = half;
            }
        }
        if (-1 == ret)
            ret = lo;

        return (ret);
    }

    /**
     * Binary search for an object
     * 
     * @param vector
     *            The vector of <code>Ordered</code> objects.
     * @param ref
     *            The name to search for.
     * @return The index at which reference was found or is to be inserted.
     */
    public static int bsearch(Vector vector, Ordered ref) {
        return (bsearch(vector, ref, 0, vector.size() - 1));
    }

    /**
     * Binary search for an object
     * 
     * @param array
     *            The array of <code>Ordered</code> objects.
     * @param ref
     *            The name to search for.
     * @param lo
     *            The lower index within which to look.
     * @param hi
     *            The upper index within which to look.
     * @return The index at which reference was found or is to be inserted.
     */
    public static int bsearch(Ordered[] array, Ordered ref, int lo, int hi) {
        int num;
        int mid;
        int half;
        int result;
        int ret;

        ret = -1;

        num = (hi - lo) + 1;
        while ((-1 == ret) && (lo <= hi)) {
            half = num / 2;
            mid = lo + ((0 != (num & 1)) ? half : half - 1);
            result = ref.compare(array[mid]);
            if (0 == result)
                ret = mid;
            else if (0 > result) {
                hi = mid - 1;
                num = ((0 != (num & 1)) ? half : half - 1);
            } else {
                lo = mid + 1;
                num = half;
            }
        }
        if (-1 == ret)
            ret = lo;

        return (ret);
    }

    /**
     * Binary search for an object
     * 
     * @param array
     *            The array of <code>Ordered</code> objects.
     * @param ref
     *            The name to search for.
     * @return The index at which reference was found or is to be inserted.
     */
    public static int bsearch(Ordered[] array, Ordered ref) {
        return (bsearch(array, ref, 0, array.length - 1));
    }
}

// HTMLParser Library - A java-based parser for HTML
// http://htmlparser.org
// Copyright (C) 2006 Derrick Oswald
//
// Revision Control Information
//
// $URL:
// https://svn.sourceforge.net/svnroot/htmlparser/trunk/lexer/src/main/java/org/htmlparser/util/sort/Ordered.java
// $
// $Author: derrickoswald $
// $Date: 2006-09-16 10:44:17 -0400 (Sat, 16 Sep 2006) $
// $Revision: 4 $
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Common Public License; either
// version 1.0 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
// Common Public License for more details.
//
// You should have received a copy of the Common Public License
// along with this library; if not, the license is available from
// the Open Source Initiative (OSI) website:
// http://opensource.org/licenses/cpl1.0.php

/**
 * Describes an object that knows about ordering. Implementors must have a
 * comparison function, which imposes a partial ordering on some collection of
 * objects. Ordered objects can be passed to a sort method (such as
 * org.htmlparser.util.sort.Sort) to allow precise control over the sort order.
 * <p>
 * An set of elements S is partially ordered if and only if
 * <code>e1.compare(e2)==0</code> implies that <code>e1.equals(e2)</code> for
 * every e1 and e2 in S.
 * <p>
 * This all goes away in JDK 1.2.
 * <p>
 * For use with java.lang.Comparable from JDK 1.2:
 * 
 * <pre>
 * public int compare(Object o1, Object o2) {
 *    return (((Ordered) o1).compare(o2));
 * }
 * </pre>
 * 
 * @see Sort
 */
interface Ordered {
    /**
     * Compares this object with another for order. Returns a negative integer,
     * zero, or a positive integer as this object is less than, equal to, or
     * greater than the second.
     * <p>
     * The implementor must ensure that
     * <code>sgn(x.compare(y)) == -sgn(y.compare(x))</code> for all x and y.
     * (This implies that <code>x.compare(y)</code> must throw an exception if
     * and only if <code>y.compare(x)</code> throws an exception.)
     * <p>
     * The implementor must also ensure that the relation is transitive:
     * <code>((x.compare(y)>0) && (y.compare(z)>0))</code> implies
     * <code>x.compare(z)>0</code>.
     * <p>
     * Finally, the implementer must ensure that <code>x.compare(y)==0</code>
     * implies that <code>sgn(x.compare(z))==sgn(y.compare(z))</code> for all z.
     * 
     * @param that
     *            The object to compare this object against.
     * @return A negative integer, zero, or a positive integer as this object is
     *         less than, equal to, or greater than the second.
     * @exception ClassCastException
     *                The arguments type prevents it from being compared by this
     *                Ordered.
     */
    public int compare(Object that);
}

// HTMLParser Library - A java-based parser for HTML
// http://htmlparser.org
// Copyright (C) 2006 Derrick Oswald
//
// Revision Control Information
//
// $URL:
// https://svn.sourceforge.net/svnroot/htmlparser/trunk/lexer/src/main/java/org/htmlparser/util/sort/Sortable.java
// $
// $Author: derrickoswald $
// $Date: 2006-09-16 10:44:17 -0400 (Sat, 16 Sep 2006) $
// $Revision: 4 $
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Common Public License; either
// version 1.0 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
// Common Public License for more details.
//
// You should have received a copy of the Common Public License
// along with this library; if not, the license is available from
// the Open Source Initiative (OSI) website:
// http://opensource.org/licenses/cpl1.0.php

/**
 * Provides a mechanism to abstract the sort process. Classes implementing this
 * interface are collections of Ordered objects that are to be sorted by the
 * Sort class and are not necessarily Vectors or Arrays of Ordered objects.
 * 
 * @see Sort
 */
interface Sortable {
    /**
     * Returns the first index of the Sortable.
     * 
     * @return The index of the first element.
     */
    public int first();

    /**
     * Returns the last index of the Sortable.
     * 
     * @return The index of the last element. If this were an array object this
     *         would be (object.length - 1).
     */
    public int last();

    /**
     * Fetch the object at the given index.
     * 
     * @param index
     *            The item number to get.
     * @param reuse
     *            If this argument is not null, it is an object acquired from a
     *            previous fetch that is no longer needed and may be returned as
     *            the result if it makes mores sense to alter and return it than
     *            to fetch or create a new element. That is, the reuse object is
     *            garbage and may be used to avoid allocating a new object if
     *            that would normally be the strategy.
     * @return The Ordered object at that index.
     */
    public Ordered fetch(int index, Ordered reuse);

    /**
     * Swaps the elements at the given indicies.
     * 
     * @param i
     *            One index.
     * @param j
     *            The other index.
     */
    public void swap(int i, int j);
}