mirror of
https://github.com/2003scape/deep-c-rsc.git
synced 2024-03-22 05:49:51 -04:00
3071 lines
89 KiB
Java
3071 lines
89 KiB
Java
![]() |
/*
|
||
|
* This file is modified by Ivan Maidanski <ivmai@ivmaisoft.com>
|
||
|
* Project name: JCGO (http://www.ivmaisoft.com/jcgo/)
|
||
|
* Class root location: $(JCGO)/goclsp/clsp_fix
|
||
|
* Origin: GNU Classpath v0.93
|
||
|
*/
|
||
|
|
||
|
/* Arrays.java -- Utility class with methods to operate on arrays
|
||
|
Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
|
||
|
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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||
|
02110-1301 USA.
|
||
|
|
||
|
Linking this library statically or dynamically with other modules is
|
||
|
making a combined work based on this library. Thus, the terms and
|
||
|
conditions of the GNU General Public License cover the whole
|
||
|
combination.
|
||
|
|
||
|
As a special exception, the copyright holders of this library give you
|
||
|
permission to link this library with independent modules to produce an
|
||
|
executable, regardless of the license terms of these independent
|
||
|
modules, and to copy and distribute the resulting executable under
|
||
|
terms of your choice, provided that you also meet, for each linked
|
||
|
independent module, the terms and conditions of the license of that
|
||
|
module. An independent module is a module which is not derived from
|
||
|
or based on this library. If you modify this library, you may extend
|
||
|
this exception to your version of the library, but you are not
|
||
|
obligated to do so. If you do not wish to do so, delete this
|
||
|
exception statement from your version. */
|
||
|
|
||
|
|
||
|
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(a[mid], key, 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;
|
||
|
|
||
|
if (null == a1 || null == a2)
|
||
|
return false;
|
||
|
|
||
|
// 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;
|
||
|
}
|
||
|
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;
|
||
|
|
||
|
if (null == a1 || null == a2)
|
||
|
return false;
|
||
|
|
||
|
// 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;
|
||
|
}
|
||
|
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;
|
||
|
|
||
|
if (null == a1 || null == a2)
|
||
|
return false;
|
||
|
|
||
|
// 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;
|
||
|
}
|
||
|
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;
|
||
|
|
||
|
if (null == a1 || null == a2)
|
||
|
return false;
|
||
|
|
||
|
// 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;
|
||
|
}
|
||
|
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;
|
||
|
|
||
|
if (null == a1 || null == a2)
|
||
|
return false;
|
||
|
|
||
|
// 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;
|
||
|
}
|
||
|
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;
|
||
|
|
||
|
if (null == a1 || null == a2)
|
||
|
return false;
|
||
|
|
||
|
// 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;
|
||
|
}
|
||
|
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;
|
||
|
|
||
|
if (null == a1 || null == a2)
|
||
|
return false;
|
||
|
|
||
|
// Must use Float.compare to take into account NaN, +-0.
|
||
|
// 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;
|
||
|
}
|
||
|
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;
|
||
|
|
||
|
if (null == a1 || null == a2)
|
||
|
return false;
|
||
|
|
||
|
// Must use Double.compare to take into account NaN, +-0.
|
||
|
// 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;
|
||
|
}
|
||
|
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;
|
||
|
|
||
|
if (null == a1 || null == a2)
|
||
|
return false;
|
||
|
|
||
|
// 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;
|
||
|
}
|
||
|
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 > toIndex
|
||
|
* @throws ArrayIndexOutOfBoundsException if fromIndex < 0
|
||
|
* || toIndex > 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 > toIndex
|
||
|
* @throws ArrayIndexOutOfBoundsException if fromIndex < 0
|
||
|
* || toIndex > 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 > toIndex
|
||
|
* @throws ArrayIndexOutOfBoundsException if fromIndex < 0
|
||
|
* || toIndex > 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 > toIndex
|
||
|
* @throws ArrayIndexOutOfBoundsException if fromIndex < 0
|
||
|
* || toIndex > 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 > toIndex
|
||
|
* @throws ArrayIndexOutOfBoundsException if fromIndex < 0
|
||
|
* || toIndex > 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 > toIndex
|
||
|
* @throws ArrayIndexOutOfBoundsException if fromIndex < 0
|
||
|
* || toIndex > 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 > toIndex
|
||
|
* @throws ArrayIndexOutOfBoundsException if fromIndex < 0
|
||
|
* || toIndex > 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 > toIndex
|
||
|
* @throws ArrayIndexOutOfBoundsException if fromIndex < 0
|
||
|
* || toIndex > 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 > toIndex
|
||
|
* @throws ArrayIndexOutOfBoundsException if fromIndex < 0
|
||
|
* || toIndex > 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 > toIndex
|
||
|
* @throws ArrayIndexOutOfBoundsException if fromIndex < 0
|
||
|
* || toIndex > a.length
|
||
|
*/
|
||
|
public static void sort(byte[] a, int fromIndex, int toIndex)
|
||
|
{
|
||
|
if (fromIndex > toIndex)
|
||
|
throw new IllegalArgumentException();
|
||
|
if (fromIndex < 0)
|
||
|
throw new ArrayIndexOutOfBoundsException();
|
||
|
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 array 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 > from && array[j - 1] > array[j]; j--)
|
||
|
swap(j, j - 1, array);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Determine a good median element.
|
||
|
int mid = from + 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 + 2 * s, array);
|
||
|
mid = med3(mid - s, mid, mid + s, array);
|
||
|
hi = med3(hi - 2 * 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;
|
||
|
c = d = from + count - 1;
|
||
|
|
||
|
// 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.
|
||
|
hi = from + count;
|
||
|
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, span, array);
|
||
|
|
||
|
span = b - a;
|
||
|
if (span > 1)
|
||
|
qsort(array, from, span);
|
||
|
|
||
|
span = d - c;
|
||
|
if (span > 1)
|
||
|
qsort(array, hi - span, 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 > toIndex
|
||
|
* @throws ArrayIndexOutOfBoundsException if fromIndex < 0
|
||
|
* || toIndex > a.length
|
||
|
*/
|
||
|
public static void sort(char[] a, int fromIndex, int toIndex)
|
||
|
{
|
||
|
if (fromIndex > toIndex)
|
||
|
throw new IllegalArgumentException();
|
||
|
if (fromIndex < 0)
|
||
|
throw new ArrayIndexOutOfBoundsException();
|
||
|
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 array 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 > from && array[j - 1] > array[j]; j--)
|
||
|
swap(j, j - 1, array);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Determine a good median element.
|
||
|
int mid = from + 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 + 2 * s, array);
|
||
|
mid = med3(mid - s, mid, mid + s, array);
|
||
|
hi = med3(hi - 2 * 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;
|
||
|
c = d = from + count - 1;
|
||
|
|
||
|
// 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.
|
||
|
hi = from + count;
|
||
|
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, span, array);
|
||
|
|
||
|
span = b - a;
|
||
|
if (span > 1)
|
||
|
qsort(array, from, span);
|
||
|
|
||
|
span = d - c;
|
||
|
if (span > 1)
|
||
|
qsort(array, hi - span, 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 > toIndex
|
||
|
* @throws ArrayIndexOutOfBoundsException if fromIndex < 0
|
||
|
* || toIndex > a.length
|
||
|
*/
|
||
|
public static void sort(short[] a, int fromIndex, int toIndex)
|
||
|
{
|
||
|
if (fromIndex > toIndex)
|
||
|
throw new IllegalArgumentException();
|
||
|
if (fromIndex < 0)
|
||
|
throw new ArrayIndexOutOfBoundsException();
|
||
|
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 array 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 > from && array[j - 1] > array[j]; j--)
|
||
|
swap(j, j - 1, array);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Determine a good median element.
|
||
|
int mid = from + 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 + 2 * s, array);
|
||
|
mid = med3(mid - s, mid, mid + s, array);
|
||
|
hi = med3(hi - 2 * 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;
|
||
|
c = d = from + count - 1;
|
||
|
|
||
|
// 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.
|
||
|
hi = from + count;
|
||
|
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, span, array);
|
||
|
|
||
|
span = b - a;
|
||
|
if (span > 1)
|
||
|
qsort(array, from, span);
|
||
|
|
||
|
span = d - c;
|
||
|
if (span > 1)
|
||
|
qsort(array, hi - span, 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 > toIndex
|
||
|
* @throws ArrayIndexOutOfBoundsException if fromIndex < 0
|
||
|
* || toIndex > a.length
|
||
|
*/
|
||
|
public static void sort(int[] a, int fromIndex, int toIndex)
|
||
|
{
|
||
|
if (fromIndex > toIndex)
|
||
|
throw new IllegalArgumentException();
|
||
|
if (fromIndex < 0)
|
||
|
throw new ArrayIndexOutOfBoundsException();
|
||
|
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 < 0, 0, or > 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 array 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 > from && array[j - 1] > array[j]; j--)
|
||
|
swap(j, j - 1, array);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Determine a good median element.
|
||
|
int mid = from + 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 + 2 * s, array);
|
||
|
mid = med3(mid - s, mid, mid + s, array);
|
||
|
hi = med3(hi - 2 * 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;
|
||
|
c = d = from + count - 1;
|
||
|
|
||
|
// 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.
|
||
|
hi = from + count;
|
||
|
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, span, array);
|
||
|
|
||
|
span = b - a;
|
||
|
if (span > 1)
|
||
|
qsort(array, from, span);
|
||
|
|
||
|
span = d - c;
|
||
|
if (span > 1)
|
||
|
qsort(array, hi - span, 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 > toIndex
|
||
|
* @throws ArrayIndexOutOfBoundsException if fromIndex < 0
|
||
|
* || toIndex > a.length
|
||
|
*/
|
||
|
public static void sort(long[] a, int fromIndex, int toIndex)
|
||
|
{
|
||
|
if (fromIndex > toIndex)
|
||
|
throw new IllegalArgumentException();
|
||
|
if (fromIndex < 0)
|
||
|
throw new ArrayIndexOutOfBoundsException();
|
||
|
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 < 0, 0, or > 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 array 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 > from && array[j - 1] > array[j]; j--)
|
||
|
swap(j, j - 1, array);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Determine a good median element.
|
||
|
int mid = from + 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 + 2 * s, array);
|
||
|
mid = med3(mid - s, mid, mid + s, array);
|
||
|
hi = med3(hi - 2 * 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;
|
||
|
c = d = from + count - 1;
|
||
|
|
||
|
// 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.
|
||
|
hi = from + count;
|
||
|
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, span, array);
|
||
|
|
||
|
span = b - a;
|
||
|
if (span > 1)
|
||
|
qsort(array, from, span);
|
||
|
|
||
|
span = d - c;
|
||
|
if (span > 1)
|
||
|
qsort(array, hi - span, 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 > toIndex
|
||
|
* @throws ArrayIndexOutOfBoundsException if fromIndex < 0
|
||
|
* || toIndex > a.length
|
||
|
*/
|
||
|
public static void sort(float[] a, int fromIndex, int toIndex)
|
||
|
{
|
||
|
if (fromIndex > toIndex)
|
||
|
throw new IllegalArgumentException();
|
||
|
if (fromIndex < 0)
|
||
|
throw new ArrayIndexOutOfBoundsException();
|
||
|
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 array 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 > from && Float.compare(array[j - 1], array[j]) > 0;
|
||
|
j--)
|
||
|
{
|
||
|
swap(j, j - 1, array);
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Determine a good median element.
|
||
|
int mid = from + 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 + 2 * s, array);
|
||
|
mid = med3(mid - s, mid, mid + s, array);
|
||
|
hi = med3(hi - 2 * 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;
|
||
|
c = d = from + count - 1;
|
||
|
|
||
|
// 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.
|
||
|
hi = from + count;
|
||
|
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, span, array);
|
||
|
|
||
|
span = b - a;
|
||
|
if (span > 1)
|
||
|
qsort(array, from, span);
|
||
|
|
||
|
span = d - c;
|
||
|
if (span > 1)
|
||
|
qsort(array, hi - span, 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 > toIndex
|
||
|
* @throws ArrayIndexOutOfBoundsException if fromIndex < 0
|
||
|
* || toIndex > a.length
|
||
|
*/
|
||
|
public static void sort(double[] a, int fromIndex, int toIndex)
|
||
|
{
|
||
|
if (fromIndex > toIndex)
|
||
|
throw new IllegalArgumentException();
|
||
|
if (fromIndex < 0)
|
||
|
throw new ArrayIndexOutOfBoundsException();
|
||
|
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 array 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 > from && Double.compare(array[j - 1], array[j]) > 0;
|
||
|
j--)
|
||
|
{
|
||
|
swap(j, j - 1, array);
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Determine a good median element.
|
||
|
int mid = from + 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 + 2 * s, array);
|
||
|
mid = med3(mid - s, mid, mid + s, array);
|
||
|
hi = med3(hi - 2 * 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;
|
||
|
c = d = from + count - 1;
|
||
|
|
||
|
// 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.
|
||
|
hi = from + count;
|
||
|
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, span, array);
|
||
|
|
||
|
span = b - a;
|
||
|
if (span > 1)
|
||
|
qsort(array, from, span);
|
||
|
|
||
|
span = d - c;
|
||
|
if (span > 1)
|
||
|
qsort(array, hi - span, 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);
|
||
|
if (fromIndex < 0)
|
||
|
throw new ArrayIndexOutOfBoundsException();
|
||
|
|
||
|
// 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 (<code>null</code> not permitted)
|
||
|
* @return a fixed-size list, changes to which "write through" to the array
|
||
|
*
|
||
|
* @throws NullPointerException if <code>a</code> is <code>null</code>.
|
||
|
* @see Serializable
|
||
|
* @see RandomAccess
|
||
|
* @see Arrays.ArrayList
|
||
|
*/
|
||
|
public static List asList(final Object[] a)
|
||
|
{
|
||
|
return new Arrays.ArrayList(a);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the hashcode of an array of long numbers. If two arrays
|
||
|
* are equal, according to <code>equals()</code>, they should have the
|
||
|
* same hashcode. The hashcode returned by the method is equal to that
|
||
|
* obtained by the corresponding <code>List</code> object. This has the same
|
||
|
* data, but represents longs in their wrapper class, <code>Long</code>.
|
||
|
* For <code>null</code>, 0 is returned.
|
||
|
*
|
||
|
* @param v an array of long numbers for which the hash code should be
|
||
|
* computed.
|
||
|
* @return the hash code of the array, or 0 if null was given.
|
||
|
* @since 1.5
|
||
|
*/
|
||
|
public static int hashCode(long[] v)
|
||
|
{
|
||
|
if (v == null)
|
||
|
return 0;
|
||
|
int result = 1;
|
||
|
for (int i = 0; i < v.length; ++i)
|
||
|
{
|
||
|
int elt = (int) (v[i] ^ (v[i] >>> 32));
|
||
|
result = 31 * result + elt;
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the hashcode of an array of integer numbers. If two arrays
|
||
|
* are equal, according to <code>equals()</code>, they should have the
|
||
|
* same hashcode. The hashcode returned by the method is equal to that
|
||
|
* obtained by the corresponding <code>List</code> object. This has the same
|
||
|
* data, but represents ints in their wrapper class, <code>Integer</code>.
|
||
|
* For <code>null</code>, 0 is returned.
|
||
|
*
|
||
|
* @param v an array of integer numbers for which the hash code should be
|
||
|
* computed.
|
||
|
* @return the hash code of the array, or 0 if null was given.
|
||
|
* @since 1.5
|
||
|
*/
|
||
|
public static int hashCode(int[] v)
|
||
|
{
|
||
|
if (v == null)
|
||
|
return 0;
|
||
|
int result = 1;
|
||
|
for (int i = 0; i < v.length; ++i)
|
||
|
result = 31 * result + v[i];
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the hashcode of an array of short numbers. If two arrays
|
||
|
* are equal, according to <code>equals()</code>, they should have the
|
||
|
* same hashcode. The hashcode returned by the method is equal to that
|
||
|
* obtained by the corresponding <code>List</code> object. This has the same
|
||
|
* data, but represents shorts in their wrapper class, <code>Short</code>.
|
||
|
* For <code>null</code>, 0 is returned.
|
||
|
*
|
||
|
* @param v an array of short numbers for which the hash code should be
|
||
|
* computed.
|
||
|
* @return the hash code of the array, or 0 if null was given.
|
||
|
* @since 1.5
|
||
|
*/
|
||
|
public static int hashCode(short[] v)
|
||
|
{
|
||
|
if (v == null)
|
||
|
return 0;
|
||
|
int result = 1;
|
||
|
for (int i = 0; i < v.length; ++i)
|
||
|
result = 31 * result + v[i];
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the hashcode of an array of characters. If two arrays
|
||
|
* are equal, according to <code>equals()</code>, they should have the
|
||
|
* same hashcode. The hashcode returned by the method is equal to that
|
||
|
* obtained by the corresponding <code>List</code> object. This has the same
|
||
|
* data, but represents chars in their wrapper class, <code>Character</code>.
|
||
|
* For <code>null</code>, 0 is returned.
|
||
|
*
|
||
|
* @param v an array of characters for which the hash code should be
|
||
|
* computed.
|
||
|
* @return the hash code of the array, or 0 if null was given.
|
||
|
* @since 1.5
|
||
|
*/
|
||
|
public static int hashCode(char[] v)
|
||
|
{
|
||
|
if (v == null)
|
||
|
return 0;
|
||
|
int result = 1;
|
||
|
for (int i = 0; i < v.length; ++i)
|
||
|
result = 31 * result + v[i];
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the hashcode of an array of bytes. If two arrays
|
||
|
* are equal, according to <code>equals()</code>, they should have the
|
||
|
* same hashcode. The hashcode returned by the method is equal to that
|
||
|
* obtained by the corresponding <code>List</code> object. This has the same
|
||
|
* data, but represents bytes in their wrapper class, <code>Byte</code>.
|
||
|
* For <code>null</code>, 0 is returned.
|
||
|
*
|
||
|
* @param v an array of bytes for which the hash code should be
|
||
|
* computed.
|
||
|
* @return the hash code of the array, or 0 if null was given.
|
||
|
* @since 1.5
|
||
|
*/
|
||
|
public static int hashCode(byte[] v)
|
||
|
{
|
||
|
if (v == null)
|
||
|
return 0;
|
||
|
int result = 1;
|
||
|
for (int i = 0; i < v.length; ++i)
|
||
|
result = 31 * result + v[i];
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the hashcode of an array of booleans. If two arrays
|
||
|
* are equal, according to <code>equals()</code>, they should have the
|
||
|
* same hashcode. The hashcode returned by the method is equal to that
|
||
|
* obtained by the corresponding <code>List</code> object. This has the same
|
||
|
* data, but represents booleans in their wrapper class,
|
||
|
* <code>Boolean</code>. For <code>null</code>, 0 is returned.
|
||
|
*
|
||
|
* @param v an array of booleans for which the hash code should be
|
||
|
* computed.
|
||
|
* @return the hash code of the array, or 0 if null was given.
|
||
|
* @since 1.5
|
||
|
*/
|
||
|
public static int hashCode(boolean[] v)
|
||
|
{
|
||
|
if (v == null)
|
||
|
return 0;
|
||
|
int result = 1;
|
||
|
for (int i = 0; i < v.length; ++i)
|
||
|
result = 31 * result + (v[i] ? 1231 : 1237);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the hashcode of an array of floats. If two arrays
|
||
|
* are equal, according to <code>equals()</code>, they should have the
|
||
|
* same hashcode. The hashcode returned by the method is equal to that
|
||
|
* obtained by the corresponding <code>List</code> object. This has the same
|
||
|
* data, but represents floats in their wrapper class, <code>Float</code>.
|
||
|
* For <code>null</code>, 0 is returned.
|
||
|
*
|
||
|
* @param v an array of floats for which the hash code should be
|
||
|
* computed.
|
||
|
* @return the hash code of the array, or 0 if null was given.
|
||
|
* @since 1.5
|
||
|
*/
|
||
|
public static int hashCode(float[] v)
|
||
|
{
|
||
|
if (v == null)
|
||
|
return 0;
|
||
|
int result = 1;
|
||
|
for (int i = 0; i < v.length; ++i)
|
||
|
result = 31 * result + Float.floatToIntBits(v[i]);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the hashcode of an array of doubles. If two arrays
|
||
|
* are equal, according to <code>equals()</code>, they should have the
|
||
|
* same hashcode. The hashcode returned by the method is equal to that
|
||
|
* obtained by the corresponding <code>List</code> object. This has the same
|
||
|
* data, but represents doubles in their wrapper class, <code>Double</code>.
|
||
|
* For <code>null</code>, 0 is returned.
|
||
|
*
|
||
|
* @param v an array of doubles for which the hash code should be
|
||
|
* computed.
|
||
|
* @return the hash code of the array, or 0 if null was given.
|
||
|
* @since 1.5
|
||
|
*/
|
||
|
public static int hashCode(double[] v)
|
||
|
{
|
||
|
if (v == null)
|
||
|
return 0;
|
||
|
int result = 1;
|
||
|
for (int i = 0; i < v.length; ++i)
|
||
|
{
|
||
|
long l = Double.doubleToLongBits(v[i]);
|
||
|
int elt = (int) (l ^ (l >>> 32));
|
||
|
result = 31 * result + elt;
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the hashcode of an array of integer numbers. If two arrays
|
||
|
* are equal, according to <code>equals()</code>, they should have the
|
||
|
* same hashcode. The hashcode returned by the method is equal to that
|
||
|
* obtained by the corresponding <code>List</code> object. This has the same
|
||
|
* data, but represents ints in their wrapper class, <code>Integer</code>.
|
||
|
* For <code>null</code>, 0 is returned.
|
||
|
*
|
||
|
* @param v an array of integer numbers for which the hash code should be
|
||
|
* computed.
|
||
|
* @return the hash code of the array, or 0 if null was given.
|
||
|
* @since 1.5
|
||
|
*/
|
||
|
public static int hashCode(Object[] v)
|
||
|
{
|
||
|
if (v == null)
|
||
|
return 0;
|
||
|
int result = 1;
|
||
|
for (int i = 0; i < v.length; ++i)
|
||
|
{
|
||
|
int elt = v[i] == null ? 0 : v[i].hashCode();
|
||
|
result = 31 * result + elt;
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/** @since 1.5 */
|
||
|
public static int deepHashCode(Object[] v)
|
||
|
{
|
||
|
if (v == null)
|
||
|
return 0;
|
||
|
int result = 1;
|
||
|
for (int i = 0; i < v.length; ++i)
|
||
|
{
|
||
|
int elt;
|
||
|
if (v[i] == null)
|
||
|
elt = 0;
|
||
|
else if (v[i] instanceof boolean[])
|
||
|
elt = hashCode((boolean[]) v[i]);
|
||
|
else if (v[i] instanceof byte[])
|
||
|
elt = hashCode((byte[]) v[i]);
|
||
|
else if (v[i] instanceof char[])
|
||
|
elt = hashCode((char[]) v[i]);
|
||
|
else if (v[i] instanceof short[])
|
||
|
elt = hashCode((short[]) v[i]);
|
||
|
else if (v[i] instanceof int[])
|
||
|
elt = hashCode((int[]) v[i]);
|
||
|
else if (v[i] instanceof long[])
|
||
|
elt = hashCode((long[]) v[i]);
|
||
|
else if (v[i] instanceof float[])
|
||
|
elt = hashCode((float[]) v[i]);
|
||
|
else if (v[i] instanceof double[])
|
||
|
elt = hashCode((double[]) v[i]);
|
||
|
else if (v[i] instanceof Object[])
|
||
|
elt = hashCode((Object[]) v[i]);
|
||
|
else
|
||
|
elt = v[i].hashCode();
|
||
|
result = 31 * result + elt;
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/** @since 1.5 */
|
||
|
public static boolean deepEquals(Object[] v1, Object[] v2)
|
||
|
{
|
||
|
if (v1 == null)
|
||
|
return v2 == null;
|
||
|
if (v2 == null || v1.length != v2.length)
|
||
|
return false;
|
||
|
|
||
|
for (int i = 0; i < v1.length; ++i)
|
||
|
{
|
||
|
Object e1 = v1[i];
|
||
|
Object e2 = v2[i];
|
||
|
|
||
|
if (e1 == e2)
|
||
|
continue;
|
||
|
if (e1 == null || e2 == null)
|
||
|
return false;
|
||
|
|
||
|
boolean check;
|
||
|
if (e1 instanceof boolean[] && e2 instanceof boolean[])
|
||
|
check = equals((boolean[]) e1, (boolean[]) e2);
|
||
|
else if (e1 instanceof byte[] && e2 instanceof byte[])
|
||
|
check = equals((byte[]) e1, (byte[]) e2);
|
||
|
else if (e1 instanceof char[] && e2 instanceof char[])
|
||
|
check = equals((char[]) e1, (char[]) e2);
|
||
|
else if (e1 instanceof short[] && e2 instanceof short[])
|
||
|
check = equals((short[]) e1, (short[]) e2);
|
||
|
else if (e1 instanceof int[] && e2 instanceof int[])
|
||
|
check = equals((int[]) e1, (int[]) e2);
|
||
|
else if (e1 instanceof long[] && e2 instanceof long[])
|
||
|
check = equals((long[]) e1, (long[]) e2);
|
||
|
else if (e1 instanceof float[] && e2 instanceof float[])
|
||
|
check = equals((float[]) e1, (float[]) e2);
|
||
|
else if (e1 instanceof double[] && e2 instanceof double[])
|
||
|
check = equals((double[]) e1, (double[]) e2);
|
||
|
else if (e1 instanceof Object[] && e2 instanceof Object[])
|
||
|
check = equals((Object[]) e1, (Object[]) e2);
|
||
|
else
|
||
|
check = e1.equals(e2);
|
||
|
if (! check)
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a String representation of the argument array. Returns "null"
|
||
|
* if <code>a</code> is null.
|
||
|
* @param v the array to represent
|
||
|
* @return a String representing this array
|
||
|
* @since 1.5
|
||
|
*/
|
||
|
public static String toString(boolean[] v)
|
||
|
{
|
||
|
if (v == null)
|
||
|
return "null";
|
||
|
StringBuilder b = new StringBuilder("[");
|
||
|
for (int i = 0; i < v.length; ++i)
|
||
|
{
|
||
|
if (i > 0)
|
||
|
b.append(", ");
|
||
|
b.append(v[i]);
|
||
|
}
|
||
|
b.append(']');
|
||
|
return b.toString();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a String representation of the argument array. Returns "null"
|
||
|
* if <code>a</code> is null.
|
||
|
* @param v the array to represent
|
||
|
* @return a String representing this array
|
||
|
* @since 1.5
|
||
|
*/
|
||
|
public static String toString(byte[] v)
|
||
|
{
|
||
|
if (v == null)
|
||
|
return "null";
|
||
|
StringBuilder b = new StringBuilder("[");
|
||
|
for (int i = 0; i < v.length; ++i)
|
||
|
{
|
||
|
if (i > 0)
|
||
|
b.append(", ");
|
||
|
b.append(v[i]);
|
||
|
}
|
||
|
b.append(']');
|
||
|
return b.toString();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a String representation of the argument array. Returns "null"
|
||
|
* if <code>a</code> is null.
|
||
|
* @param v the array to represent
|
||
|
* @return a String representing this array
|
||
|
* @since 1.5
|
||
|
*/
|
||
|
public static String toString(char[] v)
|
||
|
{
|
||
|
if (v == null)
|
||
|
return "null";
|
||
|
StringBuilder b = new StringBuilder("[");
|
||
|
for (int i = 0; i < v.length; ++i)
|
||
|
{
|
||
|
if (i > 0)
|
||
|
b.append(", ");
|
||
|
b.append(v[i]);
|
||
|
}
|
||
|
b.append(']');
|
||
|
return b.toString();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a String representation of the argument array. Returns "null"
|
||
|
* if <code>a</code> is null.
|
||
|
* @param v the array to represent
|
||
|
* @return a String representing this array
|
||
|
* @since 1.5
|
||
|
*/
|
||
|
public static String toString(short[] v)
|
||
|
{
|
||
|
if (v == null)
|
||
|
return "null";
|
||
|
StringBuilder b = new StringBuilder("[");
|
||
|
for (int i = 0; i < v.length; ++i)
|
||
|
{
|
||
|
if (i > 0)
|
||
|
b.append(", ");
|
||
|
b.append(v[i]);
|
||
|
}
|
||
|
b.append(']');
|
||
|
return b.toString();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a String representation of the argument array. Returns "null"
|
||
|
* if <code>a</code> is null.
|
||
|
* @param v the array to represent
|
||
|
* @return a String representing this array
|
||
|
* @since 1.5
|
||
|
*/
|
||
|
public static String toString(int[] v)
|
||
|
{
|
||
|
if (v == null)
|
||
|
return "null";
|
||
|
StringBuilder b = new StringBuilder("[");
|
||
|
for (int i = 0; i < v.length; ++i)
|
||
|
{
|
||
|
if (i > 0)
|
||
|
b.append(", ");
|
||
|
b.append(v[i]);
|
||
|
}
|
||
|
b.append(']');
|
||
|
return b.toString();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a String representation of the argument array. Returns "null"
|
||
|
* if <code>a</code> is null.
|
||
|
* @param v the array to represent
|
||
|
* @return a String representing this array
|
||
|
* @since 1.5
|
||
|
*/
|
||
|
public static String toString(long[] v)
|
||
|
{
|
||
|
if (v == null)
|
||
|
return "null";
|
||
|
StringBuilder b = new StringBuilder("[");
|
||
|
for (int i = 0; i < v.length; ++i)
|
||
|
{
|
||
|
if (i > 0)
|
||
|
b.append(", ");
|
||
|
b.append(v[i]);
|
||
|
}
|
||
|
b.append(']');
|
||
|
return b.toString();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a String representation of the argument array. Returns "null"
|
||
|
* if <code>a</code> is null.
|
||
|
* @param v the array to represent
|
||
|
* @return a String representing this array
|
||
|
* @since 1.5
|
||
|
*/
|
||
|
public static String toString(float[] v)
|
||
|
{
|
||
|
if (v == null)
|
||
|
return "null";
|
||
|
StringBuilder b = new StringBuilder("[");
|
||
|
for (int i = 0; i < v.length; ++i)
|
||
|
{
|
||
|
if (i > 0)
|
||
|
b.append(", ");
|
||
|
b.append(v[i]);
|
||
|
}
|
||
|
b.append(']');
|
||
|
return b.toString();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a String representation of the argument array. Returns "null"
|
||
|
* if <code>a</code> is null.
|
||
|
* @param v the array to represent
|
||
|
* @return a String representing this array
|
||
|
* @since 1.5
|
||
|
*/
|
||
|
public static String toString(double[] v)
|
||
|
{
|
||
|
if (v == null)
|
||
|
return "null";
|
||
|
StringBuilder b = new StringBuilder("[");
|
||
|
for (int i = 0; i < v.length; ++i)
|
||
|
{
|
||
|
if (i > 0)
|
||
|
b.append(", ");
|
||
|
b.append(v[i]);
|
||
|
}
|
||
|
b.append(']');
|
||
|
return b.toString();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a String representation of the argument array. Returns "null"
|
||
|
* if <code>a</code> is null.
|
||
|
* @param v the array to represent
|
||
|
* @return a String representing this array
|
||
|
* @since 1.5
|
||
|
*/
|
||
|
public static String toString(Object[] v)
|
||
|
{
|
||
|
if (v == null)
|
||
|
return "null";
|
||
|
StringBuilder b = new StringBuilder("[");
|
||
|
for (int i = 0; i < v.length; ++i)
|
||
|
{
|
||
|
if (i > 0)
|
||
|
b.append(", ");
|
||
|
b.append(v[i]);
|
||
|
}
|
||
|
b.append(']');
|
||
|
return b.toString();
|
||
|
}
|
||
|
|
||
|
private static void deepToString(Object[] v, StringBuilder b, HashSet seen)
|
||
|
{
|
||
|
b.append('[');
|
||
|
for (int i = 0; i < v.length; ++i)
|
||
|
{
|
||
|
if (i > 0)
|
||
|
b.append(", ");
|
||
|
Object elt = v[i];
|
||
|
if (elt == null)
|
||
|
b.append("null");
|
||
|
else if (elt instanceof boolean[])
|
||
|
b.append(toString((boolean[]) elt));
|
||
|
else if (elt instanceof byte[])
|
||
|
b.append(toString((byte[]) elt));
|
||
|
else if (elt instanceof char[])
|
||
|
b.append(toString((char[]) elt));
|
||
|
else if (elt instanceof short[])
|
||
|
b.append(toString((short[]) elt));
|
||
|
else if (elt instanceof int[])
|
||
|
b.append(toString((int[]) elt));
|
||
|
else if (elt instanceof long[])
|
||
|
b.append(toString((long[]) elt));
|
||
|
else if (elt instanceof float[])
|
||
|
b.append(toString((float[]) elt));
|
||
|
else if (elt instanceof double[])
|
||
|
b.append(toString((double[]) elt));
|
||
|
else if (elt instanceof Object[])
|
||
|
{
|
||
|
Object[] os = (Object[]) elt;
|
||
|
if (seen.contains(os))
|
||
|
b.append("[...]");
|
||
|
else
|
||
|
{
|
||
|
seen.add(os);
|
||
|
deepToString(os, b, seen);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
b.append(elt);
|
||
|
}
|
||
|
b.append(']');
|
||
|
}
|
||
|
|
||
|
/** @since 1.5 */
|
||
|
public static String deepToString(Object[] v)
|
||
|
{
|
||
|
if (v == null)
|
||
|
return "null";
|
||
|
HashSet seen = new HashSet();
|
||
|
StringBuilder b = new StringBuilder();
|
||
|
deepToString(v, b, seen);
|
||
|
return b.toString();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the object at the specified index in
|
||
|
* the array.
|
||
|
*
|
||
|
* @param index The index to retrieve an object from.
|
||
|
* @return The object at the array index specified.
|
||
|
*/
|
||
|
public Object get(int index)
|
||
|
{
|
||
|
return a[index];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the size of the array.
|
||
|
*
|
||
|
* @return The size.
|
||
|
*/
|
||
|
public int size()
|
||
|
{
|
||
|
return a.length;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Replaces the object at the specified index
|
||
|
* with the supplied element.
|
||
|
*
|
||
|
* @param index The index at which to place the new object.
|
||
|
* @param element The new object.
|
||
|
* @return The object replaced by this operation.
|
||
|
*/
|
||
|
public Object set(int index, Object element)
|
||
|
{
|
||
|
Object old = a[index];
|
||
|
a[index] = element;
|
||
|
return old;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if the array contains the
|
||
|
* supplied object.
|
||
|
*
|
||
|
* @param o The object to look for.
|
||
|
* @return True if the object was found.
|
||
|
*/
|
||
|
public boolean contains(Object o)
|
||
|
{
|
||
|
return lastIndexOf(o) >= 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the first index at which the
|
||
|
* object, o, occurs in the array.
|
||
|
*
|
||
|
* @param o The object to search for.
|
||
|
* @return The first relevant index.
|
||
|
*/
|
||
|
public int indexOf(Object o)
|
||
|
{
|
||
|
int size = a.length;
|
||
|
for (int i = 0; i < size; i++)
|
||
|
if (ArrayList.equals(o, a[i]))
|
||
|
return i;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the last index at which the
|
||
|
* object, o, occurs in the array.
|
||
|
*
|
||
|
* @param o The object to search for.
|
||
|
* @return The last relevant index.
|
||
|
*/
|
||
|
public int lastIndexOf(Object o)
|
||
|
{
|
||
|
int i = a.length;
|
||
|
while (--i >= 0)
|
||
|
if (ArrayList.equals(o, a[i]))
|
||
|
return i;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Transforms the list into an array of
|
||
|
* objects, by simplying cloning the array
|
||
|
* wrapped by this list.
|
||
|
*
|
||
|
* @return A clone of the internal array.
|
||
|
*/
|
||
|
public Object[] toArray()
|
||
|
{
|
||
|
return (Object[]) a.clone();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Copies the objects from this list into
|
||
|
* the supplied array. The supplied array
|
||
|
* is shrunk or enlarged to the size of the
|
||
|
* internal array, and filled with its objects.
|
||
|
*
|
||
|
* @param array The array to fill with the objects in this list.
|
||
|
* @return The array containing the objects in this list,
|
||
|
* which may or may not be == to array.
|
||
|
*/
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
}
|