gcc/libjava/java/util/Arrays.java
Bryce McKinlay d9fd7154ec Collections drop from Classpath:
2001-12-15  Bryce McKinlay  <bryce@waitaki.otago.ac.nz>

	* java/util/BitSet.java (and): Fix off-by-one bug, don't skip part of
	the bitset.
	(andNot): Likewise.
	(xor): Likewise.

2001-12-15  Bryce McKinlay  <bryce@waitaki.otago.ac.nz>

	* java/util/LinkedList.java (LinkedListItr.add): Don't skip the next
	entry.

2001-12-15  Eric Blake  <ebb9@email.byu.edu>

	* java/util/TreeMap.java (removeNode): Fix bug in node removal.

2001-12-15  Bryce McKinlay  <bryce@waitaki.otago.ac.nz>

	* java/util/AbstractCollection.java (containsAll): Use size of the
	correct collection for loop bound.
	* java/util/AbstractList.java (iterator.next): Increment pos after
	calling get on backing list.
	(listIterator.next): Likewise.
	* java/util/LinkedList.java (addLastEntry): Don't increment size before
	checking for size == 0.
	(addFirstEntry): Rearrange to match addLastEntry.
	(add): Do not increment size before inserting the new entry.

	* java/util/AbstractCollection.java (addAll): Use size of the
	correct collection for loop bound.

2001-12-15  Bryce McKinlay  <bryce@waitaki.otago.ac.nz>

	* java/util/AbstractSet.java (removeAll): Fix scoping thinko.
	* java/util/HashMap.java (putAllInternal): Set size here.
	* java/util/Hashtable.java (putAllInternal): New method. Copy contents
	of a map efficiently without calling put() or putAll().
	(Hashtable (map)): Use putAllInternal.
	(clone): Likewise.

2001-12-15  Eric Blake  <ebb9@email.byu.edu>

	* java/util/Collections.java:
	* java/util/Vector.java:
	* java/util/WeakHashMap.java: Fix spelling errors.

2001-12-15  Eric Blake  <ebb9@email.byu.edu>

	* java/util/AbstractCollection.java (removeAllInternal),
	(retainAllInternal): Add hooks for use by ArrayList.
	* java/util/AbstractList.java: Minor code updates. Fix some
	scoping.
	* java/util/AbstractMap.java: ditto
	* java/util/ArrayList.java (readObject, writeObject): ditto
	(removeAllInternal, retainAllInternal): Optimize.
	* java/util/Arrays.java: ditto
	* java/util/Collections.java: ditto. Change order of parameters
	to equals(Object, Object) to match specs.
	* java/util/Dictionary.java: Improve javadoc.
	(Dictionary): Add explicit constructor.
	* java/util/HashMap.java: Improve javadoc. Rearrange methods to
	follow order in JDK. Cleanups related to recent code migration to
	AbstractMap. Fix some scoping.
	(entrySet): Cache the result.
	(modCount): Ensure that this is updated correctly.
	* java/util/HashSet.java: Improve javadoc. Fix some scoping.
	(init): Add hooks for LinkedHashSet.
	(map): Use "" instead of Boolean.TRUE in backing map. Use
	package-private API where possible for less overhead.
	(readObject, writeObject): Fix serialization.
	* java/util/Hashtable.java: Improve javadoc. Fix some scoping.
	(entrySet, keySet, values): Cache the result.
	(modCount): Ensure that this is updated correctly.
	(contains, remove): Fix NullPointer checking to match specs.
	(class Enumeration): Make more like HashIterator.
	* java/util/IdentityHashMap.java: Minor code updates.
	(modCount): Ensure that this is updated correctly.
	(readObject, writeObject): Fix serialization.
	* java/util/LinkedHashMap.java: Minor code updates. Cleanups
	related to recent code migration to AbstractMap.
	* java/util/LinkedHashSet.java: New file.
	* java/util/LinkedList.java:
	(readObject, writeObject): Fix serialization.
	* java/util/Makefile.am: List recently added files.
	* java/util/Stack.java: Minor code updates.
	* java/util/TreeMap.java: Improve javadoc. Overhaul the class to
	be more efficient. Fix some scoping. Rearrange the methods.
	(nil): Ensure that this can be thread-safe, and make it a static
	final. Initialize it to be more useful as a sentinal node.
	(Node): Specify color in constructor.
	(deleteFixup, insertFixup): Improve comments and algorithm.
	(fabricateTree): Redesign with less overhead.
	(lowestGreaterThan): Add parameter first to make SubMap easier.
	(removeNode): Patch hole where nil was being modified. Choose
	predecessor instead of successor so in-place swap works.
	(class VerifyResult, verifyTree, verifySub, verifyError): Remove
	this dead code after verifying the class works.
	(class SubMap): Rewrite several algorithms to avoid problems with
	comparing nil.
	* java/util/TreeSet.java: Improve javadoc. Fix some scoping.
	(clone): Fix ClassCastException when cloning subSet().
	(readObject, writeObject): Fix serialization.
	* java/util/WeakHashMap.java: Improve javadoc. Fix some scoping.
	(NULL_KEY): Make it compare as null, for ease elsewhere.
	(Class WeakEntry): Rename from Entry, to avoid shadowing
	Map.Entry. Add missing toString.
	(modCount): Ensure that this is updated correctly.
	(clear, containsValue, keySet, putAll, values, WeakHashMap(Map)):
	Add missing methods and constructor.

2001-12-15  Eric Blake  <ebb9@email.byu.edu>

	* java/util/ArrayList.java (checkBoundExclusive),
	(checkBoundInclusive): Rename from range??clusive, to match
	AbstractList.
	* java/util/LinkedList.java (checkBoundsExclusive),
	(checkBoundsInclusive): ditto
	* java/util/Vector.java (checkBoundExclusive),
	(checkBoundInclusive): Move bounds checking into common methods.

2001-12-15  Eric Blake  <ebb9@email.byu.edu>

	* java/util/AbstractList.java:
	(modCount): Make sure it is updated in all needed places.
	* java/util/ArrayList.java: Improve javadoc. Implements
	RandomAccess. Add serialVersionUID. Reorder methods.
	(modCount): Make sure it is updated in all needed places.
	(rangeExclusive, rangeInclusive): Add common methods for bounds
	check.
	(isEmpty): Add missing method.
	* java/util/Collections.java: (class SynchronizedList): Make
	package visible.
	* java/util/ConcurrentModificationException.java: Improve
	javadoc.
	* java/util/EmptyStackException.java: Improve javadoc.
	* java/util/LinkedList.java: Improve javadoc.
	(modCount): Make sure it is updated in all needed places.
	(rangeExclusive, rangeInclusive): Add common methods for bounds
	check.
	* java/util/NoSuchElementException.java: Improve javadoc.
	* java/util/Stack.java: Improve javadoc. Fix synchronization
	issues.
	(modCount): Make sure it is updated in all needed places.
	* java/util/Vector.java: Improve javadoc. Fix synchronization
	issues. Implements RandomAccess. Reorder methods.
	(modCount): Make sure it is updated in all needed places.
	(setSize): Fix according to specifications: this does not dictate
	the backing array size.
	(removeAll, retainAll): Faster implementations.

2001-12-15  Eric Blake  <ebb9@email.byu.edu>

	* java/util/BitSet.java: Improve javadoc.
	(cardinality(), clear(), clear(int, int), flip(int)),
	(flip(int, int), get(int, int), intersects(BitSet), isEmpty()),
	(nextClearBit(int), nextSetBit(int), set(int, boolean)),
	(set(int, int), set(int, int, boolean)): Add new JDK 1.4 methods.
	(clone): Fix so subclasses clone correctly.

2001-12-15  Eric Blake  <ebb9@email.byu.edu>

	* java/util/AbstractCollection.java: Improve javadoc.
	(AbstractCollection()): Make constructor protected.
	(equals(Object, Object), hashCode(Object)): Add utility methods.
	* java/util/AbstractList.java: Improve javadoc.
	(AbstractList()): Make constructor protected.
	(indexOf(Object)): Call listIterator(), not listIterator(int).
	(iterator()): Follow Sun's requirement to not use listIterator(0).
	(listIterator(int)): Make AbstractListItr anonymous.
	(subList(int, int)): Add support for RandomAccess.
	(SubList.add(int, Object), SubList.remove(Object)): Fix bug with
	modCount tracking.
	(SubList.addAll(Collection)): Add missing method.
	(SubList.listIterator(int)): Fix bugs in indexing, modCount
	tracking.
	(class RandomAccessSubList): Add new class.
	* java/util/AbstractMap.java: Improve javadoc.
	(keys, values, KEYS, VALUES, ENTRIES): Consolidate common map
	fields.
	(AbstractMap()): Make constructor protected.
	(equals(Object, Object), hashCode(Object)): Add utility methods.
	(equals(Object)): Change algorithm to
	entrySet().equals(m.entrySet()), as documented by Sun.
	(keySet(), values()): Cache the collections.
	* java/util/AbstractSequentialList.java: Improve javadoc.
	(AbstractSequentialList()): Make constructor protected.
	* java/util/AbstractSet.java: Improve javadoc.
	(AbstractSet()): Make constructor protected.
	(removeAll(Collection)): Add missing method.
	* java/util/Arrays.java: Improve javadoc, rearrange method orders.
	(defaultComparator): Remove, in favor of
	Collections.compare(Object, Object, Comparator).
	(binarySearch, equals, sort): Fix natural order comparison of
	floats and doubles. Also improve Object comparison - when
	comparator is null, use natural order.
	(fill, sort): Add missing checks for IllegalArgumentException.
	(sort, qsort): Fix sorting bugs, rework the code for more
	legibility.
	(mergeSort): Inline into sort(Object[], int, int, Comparator).
	(class ArrayList): Rename from ListImpl, and make compatible with
	JDK serialization. Add methods which more efficiently override
	those of AbstractList.
	* java/util/Collections: Improve javadoc.
	(isSequential(List)): Add and use a method for deciding between
	RandomAccess and sequential algorithms on lists.
	(class Empty*, class Synchronized*, class Unmodifiable*): Make
	compliant with JDK serializability.
	(class Singleton*, class CopiesList, class RevereseComparator),
	(class UnmodifiableMap.UnmodifiableEntrySet),
	(class *RandomAccessList): New classes for serial compatibility.
	(class Empty*, class Singleton*, class CopiesList): Add methods
	which more efficiently override those of Abstract*.
	(search): Inline into binarySearch(List, Object, Comparator).
	(binarySearch): Make sequential search only do log(n) comparisons,
	instead of n.
	(copy(List, List)): Do bounds checking before starting.
	(indexOfSubList, lastIndexOfSubList, list, replaceAll, rotate),
	(swap):	Add new JDK 1.4 methods.
	(binarySearch, max, min, sort): Allow null comparator to represent
	natural ordering.
	(reverse(List)): Avoid unnecessary swap.
	(shuffle(List, Random)): Do shuffle in-place for RandomAccess
	lists.
	(SingletonList.get): Fix logic bug.
	(SingletonMap.entrySet): Make the entry immutable, and cache the
	returned set.
	(SynchronizedCollection, SynchronizedMap, UnmodifiableCollection),
	(UnmodifiableMap): Detect null pointer in construction.
	(SynchronizedMap, UnmodifiableMap): Cache collection views.
	* java/util/BasicMapEntry: Improve javadoc.

From-SVN: r48035
2001-12-15 07:47:03 +00:00

2455 lines
71 KiB
Java
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Arrays.java -- Utility class with methods to operate on arrays
Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath 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
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.
As a special exception, if you link this library with other files to
produce an executable, this library does not by itself cause the
resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why the
executable file might be covered by the GNU General Public License. */
package java.util;
import java.io.Serializable;
import java.lang.reflect.Array;
/**
* This class contains various static utility methods performing operations on
* arrays, and a method to provide a List "view" of an array to facilitate
* using arrays with Collection-based APIs. All methods throw a
* {@link NullPointerException} if the parameter array is null.
* <p>
*
* Implementations may use their own algorithms, but must obey the general
* properties; for example, the sort must be stable and n*log(n) complexity.
* Sun's implementation of sort, and therefore ours, is a tuned quicksort,
* adapted from Jon L. Bentley and M. Douglas McIlroy's "Engineering a Sort
* Function", Software-Practice and Experience, Vol. 23(11) P. 1249-1265
* (November 1993). This algorithm offers n*log(n) performance on many data
* sets that cause other quicksorts to degrade to quadratic performance.
*
* @author Original author unknown
* @author Bryce McKinlay
* @author Eric Blake <ebb9@email.byu.edu>
* @see Comparable
* @see Comparator
* @since 1.2
* @status updated to 1.4
*/
public class Arrays
{
/**
* This class is non-instantiable.
*/
private Arrays()
{
}
// binarySearch
/**
* Perform a binary search of a byte array for a key. The array must be
* sorted (as by the sort() method) - if it is not, the behaviour of this
* method is undefined, and may be an infinite loop. If the array contains
* the key more than once, any one of them may be found. Note: although the
* specification allows for an infinite loop if the array is unsorted, it
* will not happen in this implementation.
*
* @param a the array to search (must be sorted)
* @param key the value to search for
* @return the index at which the key was found, or -n-1 if it was not
* found, where n is the index of the first value higher than key or
* a.length if there is no such value.
*/
public static int binarySearch(byte[] a, byte key)
{
int low = 0;
int hi = a.length - 1;
int mid = 0;
while (low <= hi)
{
mid = (low + hi) >> 1;
final byte d = a[mid];
if (d == key)
return mid;
else if (d > key)
hi = mid - 1;
else
// This gets the insertion point right on the last loop.
low = ++mid;
}
return -mid - 1;
}
/**
* Perform a binary search of a char array for a key. The array must be
* sorted (as by the sort() method) - if it is not, the behaviour of this
* method is undefined, and may be an infinite loop. If the array contains
* the key more than once, any one of them may be found. Note: although the
* specification allows for an infinite loop if the array is unsorted, it
* will not happen in this implementation.
*
* @param a the array to search (must be sorted)
* @param key the value to search for
* @return the index at which the key was found, or -n-1 if it was not
* found, where n is the index of the first value higher than key or
* a.length if there is no such value.
*/
public static int binarySearch(char[] a, char key)
{
int low = 0;
int hi = a.length - 1;
int mid = 0;
while (low <= hi)
{
mid = (low + hi) >> 1;
final char d = a[mid];
if (d == key)
return mid;
else if (d > key)
hi = mid - 1;
else
// This gets the insertion point right on the last loop.
low = ++mid;
}
return -mid - 1;
}
/**
* Perform a binary search of a short array for a key. The array must be
* sorted (as by the sort() method) - if it is not, the behaviour of this
* method is undefined, and may be an infinite loop. If the array contains
* the key more than once, any one of them may be found. Note: although the
* specification allows for an infinite loop if the array is unsorted, it
* will not happen in this implementation.
*
* @param a the array to search (must be sorted)
* @param key the value to search for
* @return the index at which the key was found, or -n-1 if it was not
* found, where n is the index of the first value higher than key or
* a.length if there is no such value.
*/
public static int binarySearch(short[] a, short key)
{
int low = 0;
int hi = a.length - 1;
int mid = 0;
while (low <= hi)
{
mid = (low + hi) >> 1;
final short d = a[mid];
if (d == key)
return mid;
else if (d > key)
hi = mid - 1;
else
// This gets the insertion point right on the last loop.
low = ++mid;
}
return -mid - 1;
}
/**
* Perform a binary search of an int array for a key. The array must be
* sorted (as by the sort() method) - if it is not, the behaviour of this
* method is undefined, and may be an infinite loop. If the array contains
* the key more than once, any one of them may be found. Note: although the
* specification allows for an infinite loop if the array is unsorted, it
* will not happen in this implementation.
*
* @param a the array to search (must be sorted)
* @param key the value to search for
* @return the index at which the key was found, or -n-1 if it was not
* found, where n is the index of the first value higher than key or
* a.length if there is no such value.
*/
public static int binarySearch(int[] a, int key)
{
int low = 0;
int hi = a.length - 1;
int mid = 0;
while (low <= hi)
{
mid = (low + hi) >> 1;
final int d = a[mid];
if (d == key)
return mid;
else if (d > key)
hi = mid - 1;
else
// This gets the insertion point right on the last loop.
low = ++mid;
}
return -mid - 1;
}
/**
* Perform a binary search of a long array for a key. The array must be
* sorted (as by the sort() method) - if it is not, the behaviour of this
* method is undefined, and may be an infinite loop. If the array contains
* the key more than once, any one of them may be found. Note: although the
* specification allows for an infinite loop if the array is unsorted, it
* will not happen in this implementation.
*
* @param a the array to search (must be sorted)
* @param key the value to search for
* @return the index at which the key was found, or -n-1 if it was not
* found, where n is the index of the first value higher than key or
* a.length if there is no such value.
*/
public static int binarySearch(long[] a, long key)
{
int low = 0;
int hi = a.length - 1;
int mid = 0;
while (low <= hi)
{
mid = (low + hi) >> 1;
final long d = a[mid];
if (d == key)
return mid;
else if (d > key)
hi = mid - 1;
else
// This gets the insertion point right on the last loop.
low = ++mid;
}
return -mid - 1;
}
/**
* Perform a binary search of a float array for a key. The array must be
* sorted (as by the sort() method) - if it is not, the behaviour of this
* method is undefined, and may be an infinite loop. If the array contains
* the key more than once, any one of them may be found. Note: although the
* specification allows for an infinite loop if the array is unsorted, it
* will not happen in this implementation.
*
* @param a the array to search (must be sorted)
* @param key the value to search for
* @return the index at which the key was found, or -n-1 if it was not
* found, where n is the index of the first value higher than key or
* a.length if there is no such value.
*/
public static int binarySearch(float[] a, float key)
{
// Must use Float.compare to take into account NaN, +-0.
int low = 0;
int hi = a.length - 1;
int mid = 0;
while (low <= hi)
{
mid = (low + hi) >> 1;
final int r = Float.compare(a[mid], key);
if (r == 0)
return mid;
else if (r > 0)
hi = mid - 1;
else
// This gets the insertion point right on the last loop
low = ++mid;
}
return -mid - 1;
}
/**
* Perform a binary search of a double array for a key. The array must be
* sorted (as by the sort() method) - if it is not, the behaviour of this
* method is undefined, and may be an infinite loop. If the array contains
* the key more than once, any one of them may be found. Note: although the
* specification allows for an infinite loop if the array is unsorted, it
* will not happen in this implementation.
*
* @param a the array to search (must be sorted)
* @param key the value to search for
* @return the index at which the key was found, or -n-1 if it was not
* found, where n is the index of the first value higher than key or
* a.length if there is no such value.
*/
public static int binarySearch(double[] a, double key)
{
// Must use Double.compare to take into account NaN, +-0.
int low = 0;
int hi = a.length - 1;
int mid = 0;
while (low <= hi)
{
mid = (low + hi) >> 1;
final int r = Double.compare(a[mid], key);
if (r == 0)
return mid;
else if (r > 0)
hi = mid - 1;
else
// This gets the insertion point right on the last loop
low = ++mid;
}
return -mid - 1;
}
/**
* Perform a binary search of an Object array for a key, using the natural
* ordering of the elements. The array must be sorted (as by the sort()
* method) - if it is not, the behaviour of this method is undefined, and may
* be an infinite loop. Further, the key must be comparable with every item
* in the array. If the array contains the key more than once, any one of
* them may be found. Note: although the specification allows for an infinite
* loop if the array is unsorted, it will not happen in this (JCL)
* implementation.
*
* @param a the array to search (must be sorted)
* @param key the value to search for
* @return the index at which the key was found, or -n-1 if it was not
* found, where n is the index of the first value higher than key or
* a.length if there is no such value.
* @throws ClassCastException if key could not be compared with one of the
* elements of a
* @throws NullPointerException if a null element in a is compared
*/
public static int binarySearch(Object[] a, Object key)
{
return binarySearch(a, key, null);
}
/**
* Perform a binary search of an Object array for a key, using a supplied
* Comparator. The array must be sorted (as by the sort() method with the
* same Comparator) - if it is not, the behaviour of this method is
* undefined, and may be an infinite loop. Further, the key must be
* comparable with every item in the array. If the array contains the key
* more than once, any one of them may be found. Note: although the
* specification allows for an infinite loop if the array is unsorted, it
* will not happen in this (JCL) implementation.
*
* @param a the array to search (must be sorted)
* @param key the value to search for
* @param c the comparator by which the array is sorted; or null to
* use the elements' natural order
* @return the index at which the key was found, or -n-1 if it was not
* found, where n is the index of the first value higher than key or
* a.length if there is no such value.
* @throws ClassCastException if key could not be compared with one of the
* elements of a
* @throws NullPointerException if a null element is compared with natural
* ordering (only possible when c is null)
*/
public static int binarySearch(Object[] a, Object key, Comparator c)
{
int low = 0;
int hi = a.length - 1;
int mid = 0;
while (low <= hi)
{
mid = (low + hi) >> 1;
final int d = Collections.compare(key, a[mid], c);
if (d == 0)
return mid;
else if (d < 0)
hi = mid - 1;
else
// This gets the insertion point right on the last loop
low = ++mid;
}
return -mid - 1;
}
// equals
/**
* Compare two boolean arrays for equality.
*
* @param a1 the first array to compare
* @param a2 the second array to compare
* @return true if a1 and a2 are both null, or if a2 is of the same length
* as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
*/
public static boolean equals(boolean[] a1, boolean[] a2)
{
// Quick test which saves comparing elements of the same array, and also
// catches the case that both are null.
if (a1 == a2)
return true;
try
{
// If they're the same length, test each element
if (a1.length == a2.length)
{
int i = a1.length;
while (--i >= 0)
if (a1[i] != a2[i])
return false;
return true;
}
}
catch (NullPointerException e)
{
// If one is null, we get a harmless NullPointerException
}
return false;
}
/**
* Compare two byte arrays for equality.
*
* @param a1 the first array to compare
* @param a2 the second array to compare
* @return true if a1 and a2 are both null, or if a2 is of the same length
* as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
*/
public static boolean equals(byte[] a1, byte[] a2)
{
// Quick test which saves comparing elements of the same array, and also
// catches the case that both are null.
if (a1 == a2)
return true;
try
{
// If they're the same length, test each element
if (a1.length == a2.length)
{
int i = a1.length;
while (--i >= 0)
if (a1[i] != a2[i])
return false;
return true;
}
}
catch (NullPointerException e)
{
// If one is null, we get a harmless NullPointerException
}
return false;
}
/**
* Compare two char arrays for equality.
*
* @param a1 the first array to compare
* @param a2 the second array to compare
* @return true if a1 and a2 are both null, or if a2 is of the same length
* as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
*/
public static boolean equals(char[] a1, char[] a2)
{
// Quick test which saves comparing elements of the same array, and also
// catches the case that both are null.
if (a1 == a2)
return true;
try
{
// If they're the same length, test each element
if (a1.length == a2.length)
{
int i = a1.length;
while (--i >= 0)
if (a1[i] != a2[i])
return false;
return true;
}
}
catch (NullPointerException e)
{
// If one is null, we get a harmless NullPointerException
}
return false;
}
/**
* Compare two short arrays for equality.
*
* @param a1 the first array to compare
* @param a2 the second array to compare
* @return true if a1 and a2 are both null, or if a2 is of the same length
* as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
*/
public static boolean equals(short[] a1, short[] a2)
{
// Quick test which saves comparing elements of the same array, and also
// catches the case that both are null.
if (a1 == a2)
return true;
try
{
// If they're the same length, test each element
if (a1.length == a2.length)
{
int i = a1.length;
while (--i >= 0)
if (a1[i] != a2[i])
return false;
return true;
}
}
catch (NullPointerException e)
{
// If one is null, we get a harmless NullPointerException
}
return false;
}
/**
* Compare two int arrays for equality.
*
* @param a1 the first array to compare
* @param a2 the second array to compare
* @return true if a1 and a2 are both null, or if a2 is of the same length
* as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
*/
public static boolean equals(int[] a1, int[] a2)
{
// Quick test which saves comparing elements of the same array, and also
// catches the case that both are null.
if (a1 == a2)
return true;
try
{
// If they're the same length, test each element
if (a1.length == a2.length)
{
int i = a1.length;
while (--i >= 0)
if (a1[i] != a2[i])
return false;
return true;
}
}
catch (NullPointerException e)
{
// If one is null, we get a harmless NullPointerException
}
return false;
}
/**
* Compare two long arrays for equality.
*
* @param a1 the first array to compare
* @param a2 the second array to compare
* @return true if a1 and a2 are both null, or if a2 is of the same length
* as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
*/
public static boolean equals(long[] a1, long[] a2)
{
// Quick test which saves comparing elements of the same array, and also
// catches the case that both are null.
if (a1 == a2)
return true;
try
{
// If they're the same length, test each element
if (a1.length == a2.length)
{
int i = a1.length;
while (--i >= 0)
if (a1[i] != a2[i])
return false;
return true;
}
}
catch (NullPointerException e)
{
// If one is null, we get a harmless NullPointerException
}
return false;
}
/**
* Compare two float arrays for equality.
*
* @param a1 the first array to compare
* @param a2 the second array to compare
* @return true if a1 and a2 are both null, or if a2 is of the same length
* as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
*/
public static boolean equals(float[] a1, float[] a2)
{
// Quick test which saves comparing elements of the same array, and also
// catches the case that both are null.
if (a1 == a2)
return true;
// Must use Float.compare to take into account NaN, +-0.
try
{
// If they're the same length, test each element
if (a1.length == a2.length)
{
int i = a1.length;
while (--i >= 0)
if (Float.compare(a1[i], a2[i]) != 0)
return false;
return true;
}
}
catch (NullPointerException e)
{
// If one is null, we get a harmless NullPointerException
}
return false;
}
/**
* Compare two double arrays for equality.
*
* @param a1 the first array to compare
* @param a2 the second array to compare
* @return true if a1 and a2 are both null, or if a2 is of the same length
* as a1, and for each 0 <= i < a1.length, a1[i] == a2[i]
*/
public static boolean equals(double[] a1, double[] a2)
{
// Quick test which saves comparing elements of the same array, and also
// catches the case that both are null.
if (a1 == a2)
return true;
// Must use Double.compare to take into account NaN, +-0.
try
{
// If they're the same length, test each element
if (a1.length == a2.length)
{
int i = a1.length;
while (--i >= 0)
if (Double.compare(a1[i], a2[i]) != 0)
return false;
return true;
}
}
catch (NullPointerException e)
{
// If one is null, we get a harmless NullPointerException
}
return false;
}
/**
* Compare two Object arrays for equality.
*
* @param a1 the first array to compare
* @param a2 the second array to compare
* @return true if a1 and a2 are both null, or if a1 is of the same length
* as a2, and for each 0 <= i < a.length, a1[i] == null ?
* a2[i] == null : a1[i].equals(a2[i]).
*/
public static boolean equals(Object[] a1, Object[] a2)
{
// Quick test which saves comparing elements of the same array, and also
// catches the case that both are null.
if (a1 == a2)
return true;
try
{
// If they're the same length, test each element
if (a1.length == a2.length)
{
int i = a1.length;
while (--i >= 0)
if (! AbstractCollection.equals(a1[i], a2[i]))
return false;
return true;
}
}
catch (NullPointerException e)
{
// If one is null, we get a harmless NullPointerException
}
return false;
}
// fill
/**
* Fill an array with a boolean value.
*
* @param a the array to fill
* @param val the value to fill it with
*/
public static void fill(boolean[] a, boolean val)
{
fill(a, 0, a.length, val);
}
/**
* Fill a range of an array with a boolean value.
*
* @param a the array to fill
* @param fromIndex the index to fill from, inclusive
* @param toIndex the index to fill to, exclusive
* @param val the value to fill with
* @throws IllegalArgumentException if fromIndex &gt; toIndex
* @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
* || toIndex &gt; a.length
*/
public static void fill(boolean[] a, int fromIndex, int toIndex, boolean val)
{
if (fromIndex > toIndex)
throw new IllegalArgumentException();
for (int i = fromIndex; i < toIndex; i++)
a[i] = val;
}
/**
* Fill an array with a byte value.
*
* @param a the array to fill
* @param val the value to fill it with
*/
public static void fill(byte[] a, byte val)
{
fill(a, 0, a.length, val);
}
/**
* Fill a range of an array with a byte value.
*
* @param a the array to fill
* @param fromIndex the index to fill from, inclusive
* @param toIndex the index to fill to, exclusive
* @param val the value to fill with
* @throws IllegalArgumentException if fromIndex &gt; toIndex
* @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
* || toIndex &gt; a.length
*/
public static void fill(byte[] a, int fromIndex, int toIndex, byte val)
{
if (fromIndex > toIndex)
throw new IllegalArgumentException();
for (int i = fromIndex; i < toIndex; i++)
a[i] = val;
}
/**
* Fill an array with a char value.
*
* @param a the array to fill
* @param val the value to fill it with
*/
public static void fill(char[] a, char val)
{
fill(a, 0, a.length, val);
}
/**
* Fill a range of an array with a char value.
*
* @param a the array to fill
* @param fromIndex the index to fill from, inclusive
* @param toIndex the index to fill to, exclusive
* @param val the value to fill with
* @throws IllegalArgumentException if fromIndex &gt; toIndex
* @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
* || toIndex &gt; a.length
*/
public static void fill(char[] a, int fromIndex, int toIndex, char val)
{
if (fromIndex > toIndex)
throw new IllegalArgumentException();
for (int i = fromIndex; i < toIndex; i++)
a[i] = val;
}
/**
* Fill an array with a short value.
*
* @param a the array to fill
* @param val the value to fill it with
*/
public static void fill(short[] a, short val)
{
fill(a, 0, a.length, val);
}
/**
* Fill a range of an array with a short value.
*
* @param a the array to fill
* @param fromIndex the index to fill from, inclusive
* @param toIndex the index to fill to, exclusive
* @param val the value to fill with
* @throws IllegalArgumentException if fromIndex &gt; toIndex
* @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
* || toIndex &gt; a.length
*/
public static void fill(short[] a, int fromIndex, int toIndex, short val)
{
if (fromIndex > toIndex)
throw new IllegalArgumentException();
for (int i = fromIndex; i < toIndex; i++)
a[i] = val;
}
/**
* Fill an array with an int value.
*
* @param a the array to fill
* @param val the value to fill it with
*/
public static void fill(int[] a, int val)
{
fill(a, 0, a.length, val);
}
/**
* Fill a range of an array with an int value.
*
* @param a the array to fill
* @param fromIndex the index to fill from, inclusive
* @param toIndex the index to fill to, exclusive
* @param val the value to fill with
* @throws IllegalArgumentException if fromIndex &gt; toIndex
* @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
* || toIndex &gt; a.length
*/
public static void fill(int[] a, int fromIndex, int toIndex, int val)
{
if (fromIndex > toIndex)
throw new IllegalArgumentException();
for (int i = fromIndex; i < toIndex; i++)
a[i] = val;
}
/**
* Fill an array with a long value.
*
* @param a the array to fill
* @param val the value to fill it with
*/
public static void fill(long[] a, long val)
{
fill(a, 0, a.length, val);
}
/**
* Fill a range of an array with a long value.
*
* @param a the array to fill
* @param fromIndex the index to fill from, inclusive
* @param toIndex the index to fill to, exclusive
* @param val the value to fill with
* @throws IllegalArgumentException if fromIndex &gt; toIndex
* @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
* || toIndex &gt; a.length
*/
public static void fill(long[] a, int fromIndex, int toIndex, long val)
{
if (fromIndex > toIndex)
throw new IllegalArgumentException();
for (int i = fromIndex; i < toIndex; i++)
a[i] = val;
}
/**
* Fill an array with a float value.
*
* @param a the array to fill
* @param val the value to fill it with
*/
public static void fill(float[] a, float val)
{
fill(a, 0, a.length, val);
}
/**
* Fill a range of an array with a float value.
*
* @param a the array to fill
* @param fromIndex the index to fill from, inclusive
* @param toIndex the index to fill to, exclusive
* @param val the value to fill with
* @throws IllegalArgumentException if fromIndex &gt; toIndex
* @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
* || toIndex &gt; a.length
*/
public static void fill(float[] a, int fromIndex, int toIndex, float val)
{
if (fromIndex > toIndex)
throw new IllegalArgumentException();
for (int i = fromIndex; i < toIndex; i++)
a[i] = val;
}
/**
* Fill an array with a double value.
*
* @param a the array to fill
* @param val the value to fill it with
*/
public static void fill(double[] a, double val)
{
fill(a, 0, a.length, val);
}
/**
* Fill a range of an array with a double value.
*
* @param a the array to fill
* @param fromIndex the index to fill from, inclusive
* @param toIndex the index to fill to, exclusive
* @param val the value to fill with
* @throws IllegalArgumentException if fromIndex &gt; toIndex
* @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
* || toIndex &gt; a.length
*/
public static void fill(double[] a, int fromIndex, int toIndex, double val)
{
if (fromIndex > toIndex)
throw new IllegalArgumentException();
for (int i = fromIndex; i < toIndex; i++)
a[i] = val;
}
/**
* Fill an array with an Object value.
*
* @param a the array to fill
* @param val the value to fill it with
* @throws ClassCastException if val is not an instance of the element
* type of a.
*/
public static void fill(Object[] a, Object val)
{
fill(a, 0, a.length, val);
}
/**
* Fill a range of an array with an Object value.
*
* @param a the array to fill
* @param fromIndex the index to fill from, inclusive
* @param toIndex the index to fill to, exclusive
* @param val the value to fill with
* @throws ClassCastException if val is not an instance of the element
* type of a.
* @throws IllegalArgumentException if fromIndex &gt; toIndex
* @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
* || toIndex &gt; a.length
*/
public static void fill(Object[] a, int fromIndex, int toIndex, Object val)
{
if (fromIndex > toIndex)
throw new IllegalArgumentException();
for (int i = fromIndex; i < toIndex; i++)
a[i] = val;
}
// sort
// Thanks to Paul Fisher <rao@gnu.org> for finding this quicksort algorithm
// as specified by Sun and porting it to Java. The algorithm is an optimised
// quicksort, as described in Jon L. Bentley and M. Douglas McIlroy's
// "Engineering a Sort Function", Software-Practice and Experience, Vol.
// 23(11) P. 1249-1265 (November 1993). This algorithm gives n*log(n)
// performance on many arrays that would take quadratic time with a standard
// quicksort.
/**
* Performs a stable sort on the elements, arranging them according to their
* natural order.
*
* @param a the byte array to sort
*/
public static void sort(byte[] a)
{
qsort(a, 0, a.length);
}
/**
* Performs a stable sort on the elements, arranging them according to their
* natural order.
*
* @param a the byte array to sort
* @param fromIndex the first index to sort (inclusive)
* @param toIndex the last index to sort (exclusive)
* @throws IllegalArgumentException if fromIndex &gt; toIndex
* @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
* || toIndex &gt; a.length
*/
public static void sort(byte[] a, int fromIndex, int toIndex)
{
if (fromIndex > toIndex)
throw new IllegalArgumentException();
qsort(a, fromIndex, toIndex - fromIndex);
}
/**
* Finds the index of the median of three array elements.
*
* @param a the first index
* @param b the second index
* @param c the third index
* @param d the array
* @return the index (a, b, or c) which has the middle value of the three
*/
private static int med3(int a, int b, int c, byte[] d)
{
return (d[a] < d[b]
? (d[b] < d[c] ? b : d[a] < d[c] ? c : a)
: (d[b] > d[c] ? b : d[a] > d[c] ? c : a));
}
/**
* Swaps the elements at two locations of an array
*
* @param i the first index
* @param j the second index
* @param a the array
*/
private static void swap(int i, int j, byte[] a)
{
byte c = a[i];
a[i] = a[j];
a[j] = c;
}
/**
* Swaps two ranges of an array.
*
* @param i the first range start
* @param j the second range start
* @param n the element count
* @param a the array
*/
private static void vecswap(int i, int j, int n, byte[] a)
{
for ( ; n > 0; i++, j++, n--)
swap(i, j, a);
}
/**
* Performs a recursive modified quicksort.
*
* @param a the array to sort
* @param from the start index (inclusive)
* @param count the number of elements to sort
*/
private static void qsort(byte[] array, int from, int count)
{
// Use an insertion sort on small arrays.
if (count <= 7)
{
for (int i = from + 1; i < from + count; i++)
for (int j = i; j > 0 && array[j - 1] > array[j]; j--)
swap(j, j - 1, array);
return;
}
// Determine a good median element.
int mid = count / 2;
int lo = from;
int hi = from + count - 1;
if (count > 40)
{ // big arrays, pseudomedian of 9
int s = count / 8;
lo = med3(lo, lo + s, lo + s + s, array);
mid = med3(mid - s, mid, mid + s, array);
hi = med3(hi - s - s, hi - s, hi, array);
}
mid = med3(lo, mid, hi, array);
int a, b, c, d;
int comp;
// Pull the median element out of the fray, and use it as a pivot.
swap(from, mid, array);
a = b = from + 1;
c = d = hi;
// Repeatedly move b and c to each other, swapping elements so
// that all elements before index b are less than the pivot, and all
// elements after index c are greater than the pivot. a and b track
// the elements equal to the pivot.
while (true)
{
while (b <= c && (comp = array[b] - array[from]) <= 0)
{
if (comp == 0)
{
swap(a, b, array);
a++;
}
b++;
}
while (c >= b && (comp = array[c] - array[from]) >= 0)
{
if (comp == 0)
{
swap(c, d, array);
d--;
}
c--;
}
if (b > c)
break;
swap(b, c, array);
b++;
c--;
}
// Swap pivot(s) back in place, the recurse on left and right sections.
int span;
span = Math.min(a - from, b - a);
vecswap(from, b - span, span, array);
span = Math.min(d - c, hi - d - 1);
vecswap(b, hi - span + 1, span, array);
span = b - a;
if (span > 1)
qsort(array, from, span);
span = d - c;
if (span > 1)
qsort(array, hi - span + 1, span);
}
/**
* Performs a stable sort on the elements, arranging them according to their
* natural order.
*
* @param a the char array to sort
*/
public static void sort(char[] a)
{
qsort(a, 0, a.length);
}
/**
* Performs a stable sort on the elements, arranging them according to their
* natural order.
*
* @param a the char array to sort
* @param fromIndex the first index to sort (inclusive)
* @param toIndex the last index to sort (exclusive)
* @throws IllegalArgumentException if fromIndex &gt; toIndex
* @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
* || toIndex &gt; a.length
*/
public static void sort(char[] a, int fromIndex, int toIndex)
{
if (fromIndex > toIndex)
throw new IllegalArgumentException();
qsort(a, fromIndex, toIndex - fromIndex);
}
/**
* Finds the index of the median of three array elements.
*
* @param a the first index
* @param b the second index
* @param c the third index
* @param d the array
* @return the index (a, b, or c) which has the middle value of the three
*/
private static int med3(int a, int b, int c, char[] d)
{
return (d[a] < d[b]
? (d[b] < d[c] ? b : d[a] < d[c] ? c : a)
: (d[b] > d[c] ? b : d[a] > d[c] ? c : a));
}
/**
* Swaps the elements at two locations of an array
*
* @param i the first index
* @param j the second index
* @param a the array
*/
private static void swap(int i, int j, char[] a)
{
char c = a[i];
a[i] = a[j];
a[j] = c;
}
/**
* Swaps two ranges of an array.
*
* @param i the first range start
* @param j the second range start
* @param n the element count
* @param a the array
*/
private static void vecswap(int i, int j, int n, char[] a)
{
for ( ; n > 0; i++, j++, n--)
swap(i, j, a);
}
/**
* Performs a recursive modified quicksort.
*
* @param a the array to sort
* @param from the start index (inclusive)
* @param count the number of elements to sort
*/
private static void qsort(char[] array, int from, int count)
{
// Use an insertion sort on small arrays.
if (count <= 7)
{
for (int i = from + 1; i < from + count; i++)
for (int j = i; j > 0 && array[j - 1] > array[j]; j--)
swap(j, j - 1, array);
return;
}
// Determine a good median element.
int mid = count / 2;
int lo = from;
int hi = from + count - 1;
if (count > 40)
{ // big arrays, pseudomedian of 9
int s = count / 8;
lo = med3(lo, lo + s, lo + s + s, array);
mid = med3(mid - s, mid, mid + s, array);
hi = med3(hi - s - s, hi - s, hi, array);
}
mid = med3(lo, mid, hi, array);
int a, b, c, d;
int comp;
// Pull the median element out of the fray, and use it as a pivot.
swap(from, mid, array);
a = b = from + 1;
c = d = hi;
// Repeatedly move b and c to each other, swapping elements so
// that all elements before index b are less than the pivot, and all
// elements after index c are greater than the pivot. a and b track
// the elements equal to the pivot.
while (true)
{
while (b <= c && (comp = array[b] - array[from]) <= 0)
{
if (comp == 0)
{
swap(a, b, array);
a++;
}
b++;
}
while (c >= b && (comp = array[c] - array[from]) >= 0)
{
if (comp == 0)
{
swap(c, d, array);
d--;
}
c--;
}
if (b > c)
break;
swap(b, c, array);
b++;
c--;
}
// Swap pivot(s) back in place, the recurse on left and right sections.
int span;
span = Math.min(a - from, b - a);
vecswap(from, b - span, span, array);
span = Math.min(d - c, hi - d - 1);
vecswap(b, hi - span + 1, span, array);
span = b - a;
if (span > 1)
qsort(array, from, span);
span = d - c;
if (span > 1)
qsort(array, hi - span + 1, span);
}
/**
* Performs a stable sort on the elements, arranging them according to their
* natural order.
*
* @param a the short array to sort
*/
public static void sort(short[] a)
{
qsort(a, 0, a.length);
}
/**
* Performs a stable sort on the elements, arranging them according to their
* natural order.
*
* @param a the short array to sort
* @param fromIndex the first index to sort (inclusive)
* @param toIndex the last index to sort (exclusive)
* @throws IllegalArgumentException if fromIndex &gt; toIndex
* @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
* || toIndex &gt; a.length
*/
public static void sort(short[] a, int fromIndex, int toIndex)
{
if (fromIndex > toIndex)
throw new IllegalArgumentException();
qsort(a, fromIndex, toIndex - fromIndex);
}
/**
* Finds the index of the median of three array elements.
*
* @param a the first index
* @param b the second index
* @param c the third index
* @param d the array
* @return the index (a, b, or c) which has the middle value of the three
*/
private static int med3(int a, int b, int c, short[] d)
{
return (d[a] < d[b]
? (d[b] < d[c] ? b : d[a] < d[c] ? c : a)
: (d[b] > d[c] ? b : d[a] > d[c] ? c : a));
}
/**
* Swaps the elements at two locations of an array
*
* @param i the first index
* @param j the second index
* @param a the array
*/
private static void swap(int i, int j, short[] a)
{
short c = a[i];
a[i] = a[j];
a[j] = c;
}
/**
* Swaps two ranges of an array.
*
* @param i the first range start
* @param j the second range start
* @param n the element count
* @param a the array
*/
private static void vecswap(int i, int j, int n, short[] a)
{
for ( ; n > 0; i++, j++, n--)
swap(i, j, a);
}
/**
* Performs a recursive modified quicksort.
*
* @param a the array to sort
* @param from the start index (inclusive)
* @param count the number of elements to sort
*/
private static void qsort(short[] array, int from, int count)
{
// Use an insertion sort on small arrays.
if (count <= 7)
{
for (int i = from + 1; i < from + count; i++)
for (int j = i; j > 0 && array[j - 1] > array[j]; j--)
swap(j, j - 1, array);
return;
}
// Determine a good median element.
int mid = count / 2;
int lo = from;
int hi = from + count - 1;
if (count > 40)
{ // big arrays, pseudomedian of 9
int s = count / 8;
lo = med3(lo, lo + s, lo + s + s, array);
mid = med3(mid - s, mid, mid + s, array);
hi = med3(hi - s - s, hi - s, hi, array);
}
mid = med3(lo, mid, hi, array);
int a, b, c, d;
int comp;
// Pull the median element out of the fray, and use it as a pivot.
swap(from, mid, array);
a = b = from + 1;
c = d = hi;
// Repeatedly move b and c to each other, swapping elements so
// that all elements before index b are less than the pivot, and all
// elements after index c are greater than the pivot. a and b track
// the elements equal to the pivot.
while (true)
{
while (b <= c && (comp = array[b] - array[from]) <= 0)
{
if (comp == 0)
{
swap(a, b, array);
a++;
}
b++;
}
while (c >= b && (comp = array[c] - array[from]) >= 0)
{
if (comp == 0)
{
swap(c, d, array);
d--;
}
c--;
}
if (b > c)
break;
swap(b, c, array);
b++;
c--;
}
// Swap pivot(s) back in place, the recurse on left and right sections.
int span;
span = Math.min(a - from, b - a);
vecswap(from, b - span, span, array);
span = Math.min(d - c, hi - d - 1);
vecswap(b, hi - span + 1, span, array);
span = b - a;
if (span > 1)
qsort(array, from, span);
span = d - c;
if (span > 1)
qsort(array, hi - span + 1, span);
}
/**
* Performs a stable sort on the elements, arranging them according to their
* natural order.
*
* @param a the int array to sort
*/
public static void sort(int[] a)
{
qsort(a, 0, a.length);
}
/**
* Performs a stable sort on the elements, arranging them according to their
* natural order.
*
* @param a the int array to sort
* @param fromIndex the first index to sort (inclusive)
* @param toIndex the last index to sort (exclusive)
* @throws IllegalArgumentException if fromIndex &gt; toIndex
* @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
* || toIndex &gt; a.length
*/
public static void sort(int[] a, int fromIndex, int toIndex)
{
if (fromIndex > toIndex)
throw new IllegalArgumentException();
qsort(a, fromIndex, toIndex - fromIndex);
}
/**
* Finds the index of the median of three array elements.
*
* @param a the first index
* @param b the second index
* @param c the third index
* @param d the array
* @return the index (a, b, or c) which has the middle value of the three
*/
private static int med3(int a, int b, int c, int[] d)
{
return (d[a] < d[b]
? (d[b] < d[c] ? b : d[a] < d[c] ? c : a)
: (d[b] > d[c] ? b : d[a] > d[c] ? c : a));
}
/**
* Swaps the elements at two locations of an array
*
* @param i the first index
* @param j the second index
* @param a the array
*/
private static void swap(int i, int j, int[] a)
{
int c = a[i];
a[i] = a[j];
a[j] = c;
}
/**
* Swaps two ranges of an array.
*
* @param i the first range start
* @param j the second range start
* @param n the element count
* @param a the array
*/
private static void vecswap(int i, int j, int n, int[] a)
{
for ( ; n > 0; i++, j++, n--)
swap(i, j, a);
}
/**
* Compares two integers in natural order, since a - b is inadequate.
*
* @param a the first int
* @param b the second int
* @return &lt; 0, 0, or &gt; 0 accorting to the comparison
*/
private static int compare(int a, int b)
{
return a < b ? -1 : a == b ? 0 : 1;
}
/**
* Performs a recursive modified quicksort.
*
* @param a the array to sort
* @param from the start index (inclusive)
* @param count the number of elements to sort
*/
private static void qsort(int[] array, int from, int count)
{
// Use an insertion sort on small arrays.
if (count <= 7)
{
for (int i = from + 1; i < from + count; i++)
for (int j = i; j > 0 && array[j - 1] > array[j]; j--)
swap(j, j - 1, array);
return;
}
// Determine a good median element.
int mid = count / 2;
int lo = from;
int hi = from + count - 1;
if (count > 40)
{ // big arrays, pseudomedian of 9
int s = count / 8;
lo = med3(lo, lo + s, lo + s + s, array);
mid = med3(mid - s, mid, mid + s, array);
hi = med3(hi - s - s, hi - s, hi, array);
}
mid = med3(lo, mid, hi, array);
int a, b, c, d;
int comp;
// Pull the median element out of the fray, and use it as a pivot.
swap(from, mid, array);
a = b = from + 1;
c = d = hi;
// Repeatedly move b and c to each other, swapping elements so
// that all elements before index b are less than the pivot, and all
// elements after index c are greater than the pivot. a and b track
// the elements equal to the pivot.
while (true)
{
while (b <= c && (comp = compare(array[b], array[from])) <= 0)
{
if (comp == 0)
{
swap(a, b, array);
a++;
}
b++;
}
while (c >= b && (comp = compare(array[c], array[from])) >= 0)
{
if (comp == 0)
{
swap(c, d, array);
d--;
}
c--;
}
if (b > c)
break;
swap(b, c, array);
b++;
c--;
}
// Swap pivot(s) back in place, the recurse on left and right sections.
int span;
span = Math.min(a - from, b - a);
vecswap(from, b - span, span, array);
span = Math.min(d - c, hi - d - 1);
vecswap(b, hi - span + 1, span, array);
span = b - a;
if (span > 1)
qsort(array, from, span);
span = d - c;
if (span > 1)
qsort(array, hi - span + 1, span);
}
/**
* Performs a stable sort on the elements, arranging them according to their
* natural order.
*
* @param a the long array to sort
*/
public static void sort(long[] a)
{
qsort(a, 0, a.length);
}
/**
* Performs a stable sort on the elements, arranging them according to their
* natural order.
*
* @param a the long array to sort
* @param fromIndex the first index to sort (inclusive)
* @param toIndex the last index to sort (exclusive)
* @throws IllegalArgumentException if fromIndex &gt; toIndex
* @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
* || toIndex &gt; a.length
*/
public static void sort(long[] a, int fromIndex, int toIndex)
{
if (fromIndex > toIndex)
throw new IllegalArgumentException();
qsort(a, fromIndex, toIndex - fromIndex);
}
/**
* Finds the index of the median of three array elements.
*
* @param a the first index
* @param b the second index
* @param c the third index
* @param d the array
* @return the index (a, b, or c) which has the middle value of the three
*/
private static int med3(int a, int b, int c, long[] d)
{
return (d[a] < d[b]
? (d[b] < d[c] ? b : d[a] < d[c] ? c : a)
: (d[b] > d[c] ? b : d[a] > d[c] ? c : a));
}
/**
* Swaps the elements at two locations of an array
*
* @param i the first index
* @param j the second index
* @param a the array
*/
private static void swap(int i, int j, long[] a)
{
long c = a[i];
a[i] = a[j];
a[j] = c;
}
/**
* Swaps two ranges of an array.
*
* @param i the first range start
* @param j the second range start
* @param n the element count
* @param a the array
*/
private static void vecswap(int i, int j, int n, long[] a)
{
for ( ; n > 0; i++, j++, n--)
swap(i, j, a);
}
/**
* Compares two longs in natural order, since a - b is inadequate.
*
* @param a the first long
* @param b the second long
* @return &lt; 0, 0, or &gt; 0 accorting to the comparison
*/
private static int compare(long a, long b)
{
return a < b ? -1 : a == b ? 0 : 1;
}
/**
* Performs a recursive modified quicksort.
*
* @param a the array to sort
* @param from the start index (inclusive)
* @param count the number of elements to sort
*/
private static void qsort(long[] array, int from, int count)
{
// Use an insertion sort on small arrays.
if (count <= 7)
{
for (int i = from + 1; i < from + count; i++)
for (int j = i; j > 0 && array[j - 1] > array[j]; j--)
swap(j, j - 1, array);
return;
}
// Determine a good median element.
int mid = count / 2;
int lo = from;
int hi = from + count - 1;
if (count > 40)
{ // big arrays, pseudomedian of 9
int s = count / 8;
lo = med3(lo, lo + s, lo + s + s, array);
mid = med3(mid - s, mid, mid + s, array);
hi = med3(hi - s - s, hi - s, hi, array);
}
mid = med3(lo, mid, hi, array);
int a, b, c, d;
int comp;
// Pull the median element out of the fray, and use it as a pivot.
swap(from, mid, array);
a = b = from + 1;
c = d = hi;
// Repeatedly move b and c to each other, swapping elements so
// that all elements before index b are less than the pivot, and all
// elements after index c are greater than the pivot. a and b track
// the elements equal to the pivot.
while (true)
{
while (b <= c && (comp = compare(array[b], array[from])) <= 0)
{
if (comp == 0)
{
swap(a, b, array);
a++;
}
b++;
}
while (c >= b && (comp = compare(array[c], array[from])) >= 0)
{
if (comp == 0)
{
swap(c, d, array);
d--;
}
c--;
}
if (b > c)
break;
swap(b, c, array);
b++;
c--;
}
// Swap pivot(s) back in place, the recurse on left and right sections.
int span;
span = Math.min(a - from, b - a);
vecswap(from, b - span, span, array);
span = Math.min(d - c, hi - d - 1);
vecswap(b, hi - span + 1, span, array);
span = b - a;
if (span > 1)
qsort(array, from, span);
span = d - c;
if (span > 1)
qsort(array, hi - span + 1, span);
}
/**
* Performs a stable sort on the elements, arranging them according to their
* natural order.
*
* @param a the float array to sort
*/
public static void sort(float[] a)
{
qsort(a, 0, a.length);
}
/**
* Performs a stable sort on the elements, arranging them according to their
* natural order.
*
* @param a the float array to sort
* @param fromIndex the first index to sort (inclusive)
* @param toIndex the last index to sort (exclusive)
* @throws IllegalArgumentException if fromIndex &gt; toIndex
* @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
* || toIndex &gt; a.length
*/
public static void sort(float[] a, int fromIndex, int toIndex)
{
if (fromIndex > toIndex)
throw new IllegalArgumentException();
qsort(a, fromIndex, toIndex - fromIndex);
}
/**
* Finds the index of the median of three array elements.
*
* @param a the first index
* @param b the second index
* @param c the third index
* @param d the array
* @return the index (a, b, or c) which has the middle value of the three
*/
private static int med3(int a, int b, int c, float[] d)
{
return (Float.compare(d[a], d[b]) < 0
? (Float.compare(d[b], d[c]) < 0 ? b
: Float.compare(d[a], d[c]) < 0 ? c : a)
: (Float.compare(d[b], d[c]) > 0 ? b
: Float.compare(d[a], d[c]) > 0 ? c : a));
}
/**
* Swaps the elements at two locations of an array
*
* @param i the first index
* @param j the second index
* @param a the array
*/
private static void swap(int i, int j, float[] a)
{
float c = a[i];
a[i] = a[j];
a[j] = c;
}
/**
* Swaps two ranges of an array.
*
* @param i the first range start
* @param j the second range start
* @param n the element count
* @param a the array
*/
private static void vecswap(int i, int j, int n, float[] a)
{
for ( ; n > 0; i++, j++, n--)
swap(i, j, a);
}
/**
* Performs a recursive modified quicksort.
*
* @param a the array to sort
* @param from the start index (inclusive)
* @param count the number of elements to sort
*/
private static void qsort(float[] array, int from, int count)
{
// Use an insertion sort on small arrays.
if (count <= 7)
{
for (int i = from + 1; i < from + count; i++)
for (int j = i;
j > 0 && Float.compare(array[j - 1], array[j]) > 0;
j--)
{
swap(j, j - 1, array);
}
return;
}
// Determine a good median element.
int mid = count / 2;
int lo = from;
int hi = from + count - 1;
if (count > 40)
{ // big arrays, pseudomedian of 9
int s = count / 8;
lo = med3(lo, lo + s, lo + s + s, array);
mid = med3(mid - s, mid, mid + s, array);
hi = med3(hi - s - s, hi - s, hi, array);
}
mid = med3(lo, mid, hi, array);
int a, b, c, d;
int comp;
// Pull the median element out of the fray, and use it as a pivot.
swap(from, mid, array);
a = b = from + 1;
c = d = hi;
// Repeatedly move b and c to each other, swapping elements so
// that all elements before index b are less than the pivot, and all
// elements after index c are greater than the pivot. a and b track
// the elements equal to the pivot.
while (true)
{
while (b <= c && (comp = Float.compare(array[b], array[from])) <= 0)
{
if (comp == 0)
{
swap(a, b, array);
a++;
}
b++;
}
while (c >= b && (comp = Float.compare(array[c], array[from])) >= 0)
{
if (comp == 0)
{
swap(c, d, array);
d--;
}
c--;
}
if (b > c)
break;
swap(b, c, array);
b++;
c--;
}
// Swap pivot(s) back in place, the recurse on left and right sections.
int span;
span = Math.min(a - from, b - a);
vecswap(from, b - span, span, array);
span = Math.min(d - c, hi - d - 1);
vecswap(b, hi - span + 1, span, array);
span = b - a;
if (span > 1)
qsort(array, from, span);
span = d - c;
if (span > 1)
qsort(array, hi - span + 1, span);
}
/**
* Performs a stable sort on the elements, arranging them according to their
* natural order.
*
* @param a the double array to sort
*/
public static void sort(double[] a)
{
qsort(a, 0, a.length);
}
/**
* Performs a stable sort on the elements, arranging them according to their
* natural order.
*
* @param a the double array to sort
* @param fromIndex the first index to sort (inclusive)
* @param toIndex the last index to sort (exclusive)
* @throws IllegalArgumentException if fromIndex &gt; toIndex
* @throws ArrayIndexOutOfBoundsException if fromIndex &lt; 0
* || toIndex &gt; a.length
*/
public static void sort(double[] a, int fromIndex, int toIndex)
{
if (fromIndex > toIndex)
throw new IllegalArgumentException();
qsort(a, fromIndex, toIndex - fromIndex);
}
/**
* Finds the index of the median of three array elements.
*
* @param a the first index
* @param b the second index
* @param c the third index
* @param d the array
* @return the index (a, b, or c) which has the middle value of the three
*/
private static int med3(int a, int b, int c, double[] d)
{
return (Double.compare(d[a], d[b]) < 0
? (Double.compare(d[b], d[c]) < 0 ? b
: Double.compare(d[a], d[c]) < 0 ? c : a)
: (Double.compare(d[b], d[c]) > 0 ? b
: Double.compare(d[a], d[c]) > 0 ? c : a));
}
/**
* Swaps the elements at two locations of an array
*
* @param i the first index
* @param j the second index
* @param a the array
*/
private static void swap(int i, int j, double[] a)
{
double c = a[i];
a[i] = a[j];
a[j] = c;
}
/**
* Swaps two ranges of an array.
*
* @param i the first range start
* @param j the second range start
* @param n the element count
* @param a the array
*/
private static void vecswap(int i, int j, int n, double[] a)
{
for ( ; n > 0; i++, j++, n--)
swap(i, j, a);
}
/**
* Performs a recursive modified quicksort.
*
* @param a the array to sort
* @param from the start index (inclusive)
* @param count the number of elements to sort
*/
private static void qsort(double[] array, int from, int count)
{
// Use an insertion sort on small arrays.
if (count <= 7)
{
for (int i = from + 1; i < from + count; i++)
for (int j = i;
j > 0 && Double.compare(array[j - 1], array[j]) > 0;
j--)
{
swap(j, j - 1, array);
}
return;
}
// Determine a good median element.
int mid = count / 2;
int lo = from;
int hi = from + count - 1;
if (count > 40)
{ // big arrays, pseudomedian of 9
int s = count / 8;
lo = med3(lo, lo + s, lo + s + s, array);
mid = med3(mid - s, mid, mid + s, array);
hi = med3(hi - s - s, hi - s, hi, array);
}
mid = med3(lo, mid, hi, array);
int a, b, c, d;
int comp;
// Pull the median element out of the fray, and use it as a pivot.
swap(from, mid, array);
a = b = from + 1;
c = d = hi;
// Repeatedly move b and c to each other, swapping elements so
// that all elements before index b are less than the pivot, and all
// elements after index c are greater than the pivot. a and b track
// the elements equal to the pivot.
while (true)
{
while (b <= c && (comp = Double.compare(array[b], array[from])) <= 0)
{
if (comp == 0)
{
swap(a, b, array);
a++;
}
b++;
}
while (c >= b && (comp = Double.compare(array[c], array[from])) >= 0)
{
if (comp == 0)
{
swap(c, d, array);
d--;
}
c--;
}
if (b > c)
break;
swap(b, c, array);
b++;
c--;
}
// Swap pivot(s) back in place, the recurse on left and right sections.
int span;
span = Math.min(a - from, b - a);
vecswap(from, b - span, span, array);
span = Math.min(d - c, hi - d - 1);
vecswap(b, hi - span + 1, span, array);
span = b - a;
if (span > 1)
qsort(array, from, span);
span = d - c;
if (span > 1)
qsort(array, hi - span + 1, span);
}
/**
* Sort an array of Objects according to their natural ordering. The sort is
* guaranteed to be stable, that is, equal elements will not be reordered.
* The sort algorithm is a mergesort with the merge omitted if the last
* element of one half comes before the first element of the other half. This
* algorithm gives guaranteed O(n*log(n)) time, at the expense of making a
* copy of the array.
*
* @param a the array to be sorted
* @throws ClassCastException if any two elements are not mutually
* comparable
* @throws NullPointerException if an element is null (since
* null.compareTo cannot work)
* @see Comparable
*/
public static void sort(Object[] a)
{
sort(a, 0, a.length, null);
}
/**
* Sort an array of Objects according to a Comparator. The sort is
* guaranteed to be stable, that is, equal elements will not be reordered.
* The sort algorithm is a mergesort with the merge omitted if the last
* element of one half comes before the first element of the other half. This
* algorithm gives guaranteed O(n*log(n)) time, at the expense of making a
* copy of the array.
*
* @param a the array to be sorted
* @param c a Comparator to use in sorting the array; or null to indicate
* the elements' natural order
* @throws ClassCastException if any two elements are not mutually
* comparable by the Comparator provided
* @throws NullPointerException if a null element is compared with natural
* ordering (only possible when c is null)
*/
public static void sort(Object[] a, Comparator c)
{
sort(a, 0, a.length, c);
}
/**
* Sort an array of Objects according to their natural ordering. The sort is
* guaranteed to be stable, that is, equal elements will not be reordered.
* The sort algorithm is a mergesort with the merge omitted if the last
* element of one half comes before the first element of the other half. This
* algorithm gives guaranteed O(n*log(n)) time, at the expense of making a
* copy of the array.
*
* @param a the array to be sorted
* @param fromIndex the index of the first element to be sorted
* @param toIndex the index of the last element to be sorted plus one
* @throws ClassCastException if any two elements are not mutually
* comparable
* @throws NullPointerException if an element is null (since
* null.compareTo cannot work)
* @throws ArrayIndexOutOfBoundsException, if fromIndex and toIndex
* are not in range.
* @throws IllegalArgumentException if fromIndex > toIndex
*/
public static void sort(Object[] a, int fromIndex, int toIndex)
{
sort(a, fromIndex, toIndex, null);
}
/**
* Sort an array of Objects according to a Comparator. The sort is
* guaranteed to be stable, that is, equal elements will not be reordered.
* The sort algorithm is a mergesort with the merge omitted if the last
* element of one half comes before the first element of the other half. This
* algorithm gives guaranteed O(n*log(n)) time, at the expense of making a
* copy of the array.
*
* @param a the array to be sorted
* @param fromIndex the index of the first element to be sorted
* @param toIndex the index of the last element to be sorted plus one
* @param c a Comparator to use in sorting the array; or null to indicate
* the elements' natural order
* @throws ClassCastException if any two elements are not mutually
* comparable by the Comparator provided
* @throws ArrayIndexOutOfBoundsException, if fromIndex and toIndex
* are not in range.
* @throws IllegalArgumentException if fromIndex > toIndex
* @throws NullPointerException if a null element is compared with natural
* ordering (only possible when c is null)
*/
public static void sort(Object[] a, int fromIndex, int toIndex, Comparator c)
{
if (fromIndex > toIndex)
throw new IllegalArgumentException("fromIndex " + fromIndex
+ " > toIndex " + toIndex);
// In general, the code attempts to be simple rather than fast, the
// idea being that a good optimising JIT will be able to optimise it
// better than I can, and if I try it will make it more confusing for
// the JIT. First presort the array in chunks of length 6 with insertion
// sort. A mergesort would give too much overhead for this length.
for (int chunk = fromIndex; chunk < toIndex; chunk += 6)
{
int end = Math.min(chunk + 6, toIndex);
for (int i = chunk + 1; i < end; i++)
{
if (Collections.compare(a[i - 1], a[i], c) > 0)
{
// not already sorted
int j = i;
Object elem = a[j];
do
{
a[j] = a[j - 1];
j--;
}
while (j > chunk
&& Collections.compare(a[j - 1], elem, c) > 0);
a[j] = elem;
}
}
}
int len = toIndex - fromIndex;
// If length is smaller or equal 6 we are done.
if (len <= 6)
return;
Object[] src = a;
Object[] dest = new Object[len];
Object[] t = null; // t is used for swapping src and dest
// The difference of the fromIndex of the src and dest array.
int srcDestDiff = -fromIndex;
// The merges are done in this loop
for (int size = 6; size < len; size <<= 1)
{
for (int start = fromIndex; start < toIndex; start += size << 1)
{
// mid is the start of the second sublist;
// end the start of the next sublist (or end of array).
int mid = start + size;
int end = Math.min(toIndex, mid + size);
// The second list is empty or the elements are already in
// order - no need to merge
if (mid >= end
|| Collections.compare(src[mid - 1], src[mid], c) <= 0)
{
System.arraycopy(src, start,
dest, start + srcDestDiff, end - start);
// The two halves just need swapping - no need to merge
}
else if (Collections.compare(src[start], src[end - 1], c) > 0)
{
System.arraycopy(src, start,
dest, end - size + srcDestDiff, size);
System.arraycopy(src, mid,
dest, start + srcDestDiff, end - mid);
}
else
{
// Declare a lot of variables to save repeating
// calculations. Hopefully a decent JIT will put these
// in registers and make this fast
int p1 = start;
int p2 = mid;
int i = start + srcDestDiff;
// The main merge loop; terminates as soon as either
// half is ended
while (p1 < mid && p2 < end)
{
dest[i++] =
src[(Collections.compare(src[p1], src[p2], c) <= 0
? p1++ : p2++)];
}
// Finish up by copying the remainder of whichever half
// wasn't finished.
if (p1 < mid)
System.arraycopy(src, p1, dest, i, mid - p1);
else
System.arraycopy(src, p2, dest, i, end - p2);
}
}
// swap src and dest ready for the next merge
t = src;
src = dest;
dest = t;
fromIndex += srcDestDiff;
toIndex += srcDestDiff;
srcDestDiff = -srcDestDiff;
}
// make sure the result ends up back in the right place. Note
// that src and dest may have been swapped above, so src
// contains the sorted array.
if (src != a)
{
// Note that fromIndex == 0.
System.arraycopy(src, 0, a, srcDestDiff, toIndex);
}
}
/**
* Returns a list "view" of the specified array. This method is intended to
* make it easy to use the Collections API with existing array-based APIs and
* programs. Changes in the list or the array show up in both places. The
* list does not support element addition or removal, but does permit
* value modification. The returned list implements both Serializable and
* RandomAccess.
*
* @param a the array to return a view of
* @return a fixed-size list, changes to which "write through" to the array
* @see Serializable
* @see RandomAccess
* @see Arrays.ArrayList
*/
public static List asList(final Object[] a)
{
return new Arrays.ArrayList(a);
}
/**
* Inner class used by {@link #asList(Object[])} to provide a list interface
* to an array. The name, though it clashes with java.util.ArrayList, is
* Sun's choice for Serialization purposes. Element addition and removal
* is prohibited, but values can be modified.
*
* @author Eric Blake <ebb9@email.byu.edu>
* @status updated to 1.4
*/
private static final class ArrayList extends AbstractList
implements Serializable, RandomAccess
{
// We override the necessary methods, plus others which will be much
// more efficient with direct iteration rather than relying on iterator().
/**
* Compatible with JDK 1.4.
*/
private static final long serialVersionUID = -2764017481108945198L;
/**
* The array we are viewing.
* @serial the array
*/
private final Object[] a;
/**
* Construct a list view of the array.
* @param a the array to view
* @throws NullPointerException if a is null
*/
ArrayList(Object[] a)
{
// We have to explicitly check.
if (a == null)
throw new NullPointerException();
this.a = a;
}
public Object get(int index)
{
return a[index];
}
public int size()
{
return a.length;
}
public Object set(int index, Object element)
{
Object old = a[index];
a[index] = element;
return old;
}
public boolean contains(Object o)
{
return lastIndexOf(o) >= 0;
}
public int indexOf(Object o)
{
int size = a.length;
for (int i = 0; i < size; i++)
if (equals(o, a[i]))
return i;
return -1;
}
public int lastIndexOf(Object o)
{
int i = a.length;
while (--i >= 0)
if (equals(o, a[i]))
return i;
return -1;
}
public Object[] toArray()
{
return (Object[]) a.clone();
}
public Object[] toArray(Object[] array)
{
int size = a.length;
if (array.length < size)
array = (Object[])
Array.newInstance(array.getClass().getComponentType(), size);
else if (array.length > size)
array[size] = null;
System.arraycopy(a, 0, array, 0, size);
return array;
}
}
}