package prefuse.util;
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.Comparator;
import java.util.Random;
import java.util.StringTokenizer;
/**
* Library of supplementary array routines not
* supported by the java.util.Arrays class.
*
* @author jeffrey heer
*/
public abstract class ArrayLib {
/**
* Arrays with lengths beneath this value will be insertion sorted.
*/
public static final int SORT_THRESHOLD = 30;
// ------------------------------------------------------------------------
// Shuffle
/**
* Randomly permute the contents of an array.
* @param a the array to shuffle
* @param r the source of randomness to use
*/
public static final void shuffle(int[] a, Random r) {
shuffle(a, 0, a.length, r);
}
/**
* Randomly permute the contents of a range an array.
* @param a the array to shuffle
* @param start the starting index of the range to shuffle
* @param len then length of the range to shuffle
* @param r the source of randomness to use
*/
public static final void shuffle(int[] a, int start, int len, Random r) {
for ( int i=start+len; --i>0; ) {
int t = a[i], j = r.nextInt(i);
a[i] = a[j];
a[j] = t;
}
}
/**
* Randomly permute the contents of an array.
* @param a the array to shuffle
* @param r the source of randomness to use
*/
public static final void shuffle(long[] a, Random r) {
shuffle(a, 0, a.length, r);
}
/**
* Randomly permute the contents of a range an array.
* @param a the array to shuffle
* @param start the starting index of the range to shuffle
* @param len then length of the range to shuffle
* @param r the source of randomness to use
*/
public static final void shuffle(long[] a, int start, int len, Random r) {
for ( int i=start+len; i>1; --i ) {
long t = a[i];
int j = r.nextInt(i);
a[i] = a[j];
a[j] = t;
}
}
/**
* Randomly permute the contents of an array.
* @param a the array to shuffle
* @param r the source of randomness to use
*/
public static final void shuffle(float[] a, Random r) {
shuffle(a, 0, a.length, r);
}
/**
* Randomly permute the contents of a range an array.
* @param a the array to shuffle
* @param start the starting index of the range to shuffle
* @param len then length of the range to shuffle
* @param r the source of randomness to use
*/
public static final void shuffle(float[] a, int start, int len, Random r) {
for ( int i=start+len; i>1; --i ) {
float t = a[i];
int j = r.nextInt(i);
a[i] = a[j];
a[j] = t;
}
}
/**
* Randomly permute the contents of an array.
* @param a the array to shuffle
* @param r the source of randomness to use
*/
public static final void shuffle(double[] a, Random r) {
shuffle(a, 0, a.length, r);
}
/**
* Randomly permute the contents of a range an array.
* @param a the array to shuffle
* @param start the starting index of the range to shuffle
* @param len then length of the range to shuffle
* @param r the source of randomness to use
*/
public static final void shuffle(double[] a, int start, int len, Random r) {
for ( int i=start+len; i>1; --i ) {
double t = a[i];
int j = r.nextInt(i);
a[i] = a[j];
a[j] = t;
}
}
/**
* Randomly permute the contents of an array.
* @param a the array to shuffle
* @param r the source of randomness to use
*/
public static final void shuffle(Object[] a, Random r) {
shuffle(a, 0, a.length, r);
}
/**
* Randomly permute the contents of a range an array.
* @param a the array to shuffle
* @param start the starting index of the range to shuffle
* @param len then length of the range to shuffle
* @param r the source of randomness to use
*/
public static final void shuffle(Object[] a, int start, int len, Random r) {
for ( int i=start+len; i>1; --i ) {
Object t = a[i];
int j = r.nextInt(i);
a[i] = a[j];
a[j] = t;
}
}
// ------------------------------------------------------------------------
// Max / Min / Sum
/**
* Find the maximum value in an array.
* @param a the array
* @return the maximum value in the array
*/
public static final double max(double[] a) {
double max = Double.NEGATIVE_INFINITY;
for ( int i=0; i<a.length; ++i ) {
if ( a[i] > max )
max = a[i];
}
return max;
}
/**
* Find the minimum value in an array.
* @param a the array
* @return the minimum value in the array
*/
public static final double min(double[] a) {
double min = Double.POSITIVE_INFINITY;
for ( int i=0; i<a.length; ++i ) {
if ( a[i] < min )
min = a[i];
}
return min;
}
/**
* Compute the sum of the values in an array.
* @param a the array
* @return the sum of the values in the array
*/
public static final double sum(double[] a) {
double sum = 0;
for ( int i=0; i<a.length; ++i ) {
sum += a[i];
}
return sum;
}
//// -----------------------------------------------
//// -- Searching Functions ------------------------
/**
* Perform a binary search over a sorted array for the given key.
* @param a the array to search
* @param key the key to search for
* @return the index of the given key if it exists in the array,
* otherwise -1 times the index value at the insertion point that
* would be used if the key were added to the array.
*/
public static final int binarySearch(int[] a, int key) {
int x1 = 0;
int x2 = a.length;
int i = x2 / 2;
while (x1 < x2) {
if (a[i] == key) {
return i;
} else if (a[i] < key) {
x1 = i + 1;
} else {
x2 = i;
}
i = x1 + (x2 - x1) / 2;
}
return -1*(i+1);
}
/**
* Perform a binary search over a sorted range of an array for the given
* key. The range is assumed to start at index 0.
* @param a the array to search
* @param key the key to search for
* @param length the the length of the range to search over.
* @return the index of the given key if it exists in the array,
* otherwise -1 times the index value at the insertion point that
* would be used if the key were added to the array.
*/
public static final int binarySearch(int[] a, int key, int length) {
int x1 = 0;
int x2 = length;
int i = x2 / 2;
while (x1 < x2) {
if (a[i] == key) {
return i;
} else if (a[i] < key) {
x1 = i + 1;
} else {
x2 = i;
}
i = x1 + (x2 - x1) / 2;
}
return -1*(i+1);
}
/**
* Perform a binary search over a sorted range of an array for the given
* key.
* @param a the array to search
* @param key the key to search for
* @param begin the starting index of the range
* @param end the ending index of the range, exclusive
* @return the index of the given key if it exists in the array,
* otherwise -1 times the index value at the insertion point that
* would be used if the key were added to the array.
*/
public static final int binarySearch(int[] a, int key, int begin, int end) {
int x1 = begin;
int x2 = end;
int i = x1 + (x2 - x1) / 2;
while (x1 < x2) {
if (a[i] == key) {
return i;
} else if (a[i] < key) {
x1 = i + 1;
} else {
x2 = i;
}
i = x1 + (x2 - x1) / 2;
}
return -1*(i+1);
}
/**
* Perform a binary search over a sorted array for the given key.
* @param a the array to search
* @param key the key to search for
* @return the index of the given key if it exists in the array,
* otherwise -1 times the index value at the insertion point that
* would be used if the key were added to the array.
*/
public static final int binarySearch(Object[] a, Object key) {
int x1 = 0;
int x2 = a.length;
int i = x2 / 2, c;
while (x1 < x2) {
c = ((Comparable)a[i]).compareTo(key);
if (c == 0) {
return i;
} else if (c < 0) {
x1 = i + 1;
} else {
x2 = i;
}
i = x1 + (x2 - x1) / 2;
}
return -1*(i+1);
}
/**
* Perform a binary search over a sorted range of an array for the given
* key. The range is assumed to start at index 0.
* @param a the array to search
* @param key the key to search for
* @param length the the length of the range to search over.
* @return the index of the given key if it exists in the array,
* otherwise -1 times the index value at the insertion point that
* would be used if the key were added to the array.
*/
public static final int binarySearch(Object[] a, Object key, int length) {
int x1 = 0;
int x2 = length;
int i = x2 / 2, c;
while (x1 < x2) {
c = ((Comparable)a[i]).compareTo(key);
if (c == 0) {
return i;
} else if (c < 0) {
x1 = i + 1;
} else {
x2 = i;
}
i = x1 + (x2 - x1) / 2;
}
return -1*(i+1);
}
/**
* Perform a binary search over a sorted range of an array for the given
* key.
* @param a the array to search
* @param key the key to search for
* @param begin the starting index of the range
* @param end the ending index of the range, exclusive
* @return the index of the given key if it exists in the array,
* otherwise -1 times the index value at the insertion point that
* would be used if the key were added to the array.
*/
public static final int binarySearch(Object[] a, Object key, int begin, int end) {
int x1 = begin;
int x2 = end;
int i = x1 + (x2 - x1) / 2, c;
while (x1 < x2) {
c = ((Comparable)a[i]).compareTo(key);
if (c == 0) {
return i;
} else if (c < 0) {
x1 = i + 1;
} else {
x2 = i;
}
i = x1 + (x2 - x1) / 2;
}
return -1*(i+1);
}
/**
* Perform a binary search over a sorted array for the given key.
* @param a the array to search
* @param key the key to search for
* @param cp the comparator to use to compare key values
* @return the index of the given key if it exists in the array,
* otherwise -1 times the index value at the insertion point that
* would be used if the key were added to the array.
*/
public static final int binarySearch(Object[] a, Object key, Comparator cp) {
int x1 = 0;
int x2 = a.length;
int i = x2 / 2, c;
while (x1 < x2) {
c = cp.compare(a[i], key);
if (c == 0) {
return i;
} else if (c < 0) {
x1 = i + 1;
} else {
x2 = i;
}
i = x1 + (x2 - x1) / 2;
}
return -1*(i+1);
}
/**
* Perform a binary search over a sorted range of an array for the given
* key. The range is assumed to start at index 0.
* @param a the array to search
* @param key the key to search for
* @param cp the comparator to use to compare key values
* @param length the the length of the range to search over.
* @return the index of the given key if it exists in the array,
* otherwise -1 times the index value at the insertion point that
* would be used if the key were added to the array.
*/
public static final int binarySearch(Object[] a, Object key, Comparator cp, int length) {
int x1 = 0;
int x2 = length;
int i = x2 / 2, c;
while (x1 < x2) {
c = cp.compare(a[i], key);
if (c == 0) {
return i;
} else if (c < 0) {
x1 = i + 1;
} else {
x2 = i;
}
i = x1 + (x2 - x1) / 2;
}
return -1*(i+1);
}
/**
* Perform a binary search over a sorted range of an array for the given
* key.
* @param a the array to search
* @param key the key to search for
* @param cp the comparator to use to compare key values
* @param begin the starting index of the range
* @param end the ending index of the range, exclusive
* @return the index of the given key if it exists in the array,
* otherwise -1 times the index value at the insertion point that
* would be used if the key were added to the array.
*/
public static final int binarySearch(Object[] a, Object key, Comparator cp, int begin, int end) {
int x1 = begin;
int x2 = end;
int i = x1 + (x2 - x1) / 2, c;
while (x1 < x2) {
c = cp.compare(a[i], key);
if (c == 0) {
return i;
} else if (c < 0) {
x1 = i + 1;
} else {
x2 = i;
}
i = x1 + (x2 - x1) / 2;
}
return -1*(i+1);
}
//// -----------------------------------------------
//// -- Finding Functions --------------------------
/**
* Linearly search an array for a given key value.
* @param a the array to search
* @param key the key to search for
* @return the index of the first occurrence of the key in the array,
* of -1 if the key is not found.
*/
public static final int find(int[] a, int key) {
for (int i = 0; i < a.length; i++) {
if (a[i] == key) {
return i;
}
}
return -1;
}
/**
* Linearly search an array range for a given key value. Assumes that
* the range begins at index 0.
* @param a the array to search
* @param key the key to search for
* @param length the length of the range to search over
* @return the index of the first occurrence of the key in the array,
* of -1 if the key is not found.
*/
public static final int find(int[] a, int key, int length) {
for (int i = 0; i < length; i++) {
if (a[i] == key) {
return i;
}
}
return -1;
}
/**
* Linearly search an array range for a given key value.
* @param a the array to search
* @param key the key to search for
* @param begin the starting index of the range
* @param end the ending index of the range, exclusive
* @return the index of the first occurrence of the key in the array,
* of -1 if the key is not found.
*/
public static final int find(int[] a, int key, int begin, int end) {
for (int i = begin; i < end; i++) {
if (a[i] == key) {
return i;
}
}
return -1;
}
//// -----------------------------------------------
//// -- Resizing Functions -------------------------
/**
* Resize the given array as needed to meet a target size.
* @param a the array to potentially resize
* @param size the minimum size of the target array
* @return the resized array, if the original array meets the size
* requirement, it is simply return, otherwise a new array is
* allocated and the contents of the original array are copied over.
*/
public static final int[] resize(int[] a, int size) {
if ( a.length >= size ) return a;
int[] b = new int[size];
System.arraycopy(a, 0, b, 0, a.length);
return b;
}
/**
* Resize the given array as needed to meet a target size.
* @param a the array to potentially resize
* @param size the minimum size of the target array
* @return the resized array, if the original array meets the size
* requirement, it is simply return, otherwise a new array is
* allocated and the contents of the original array are copied over.
*/
public static final float[] resize(float[] a, int size) {
if ( a.length >= size ) return a;
float[] b = new float[size];
System.arraycopy(a, 0, b, 0, a.length);
return b;
}
/**
* Resize the given array as needed to meet a target size.
* @param a the array to potentially resize
* @param size the minimum size of the target array
* @return the resized array, if the original array meets the size
* requirement, it is simply return, otherwise a new array is
* allocated and the contents of the original array are copied over.
*/
public static final double[] resize(double[] a, int size) {
if ( a.length >= size ) return a;
double[] b = new double[size];
System.arraycopy(a, 0, b, 0, a.length);
return b;
}
/**
* Resize the given array as needed to meet a target size.
* @param a the array to potentially resize
* @param size the minimum size of the target array
* @return the resized array, if the original array meets the size
* requirement, it is simply return, otherwise a new array is
* allocated and the contents of the original array are copied over.
*/
public static final Object[] resize(Object[] a, int size) {
if ( a.length >= size ) return a;
Object[] b = new Object[size];
System.arraycopy(a, 0, b, 0, a.length);
return b;
}
/**
* Trims an array to be exactly the target a size.
* @param a the array to trim
* @param size the desired size of the array. This value must be lesser
* than or equal to the size of the input array.
* @return a trimmed array instance
*/
public static final int[] trim(int[] a, int size) {
//assert (size <= a.length);
if ( a.length == size ) {
return a;
} else {
int[] b = new int[size];
System.arraycopy(a, 0, b, 0, size);
return b;
}
}
/**
* Trims an array to be exactly the target a size.
* @param a the array to trim
* @param size the desired size of the array. This value must be lesser
* than or equal to the size of the input array.
* @return a trimmed array instance
*/
public static final float[] trim(float[] a, int size) {
//assert (size <= a.length);
if ( a.length == size ) {
return a;
} else {
float[] b = new float[size];
System.arraycopy(a, 0, b, 0, size);
return b;
}
}
/**
* Trims an array to be exactly the target a size.
* @param a the array to trim
* @param size the desired size of the array. This value must be lesser
* than or equal to the size of the input array.
* @return a trimmed array instance
*/
public static final double[] trim(double[] a, int size) {
//assert (size <= a.length);
if ( a.length == size ) {
return a;
} else {
double[] b = new double[size];
System.arraycopy(a, 0, b, 0, size);
return b;
}
}
/**
* Trims an array to be exactly the target a size.
* @param a the array to trim
* @param size the desired size of the array. This value must be lesser
* than or equal to the size of the input array.
* @return a trimmed array instance
*/
public static final Object[] trim(Object[] a, int size) {
//assert (size <= a.length);
if ( a.length == size ) {
return a;
} else {
Object[] b = new Object[size];
System.arraycopy(a, 0, b, 0, size);
return b;
}
}
//// -----------------------------------------------
//// -- Sorting Functions --------------------------
// -- int / double sorting ------------------------------------------
/**
* Sort two arrays simultaneously, using the sort order of the values
* in the first array to determine the sort order for both arrays.
* @param a the array to sort by
* @param b the array to re-arrange based on the sort order of the
* first array.
*/
public static final void sort(int[] a, double[] b) {
mergesort(a, b, 0, a.length - 1);
}
/**
* Sort two arrays simultaneously, using the sort order of the values
* in the first array to determine the sort order for both arrays.
* @param a the array to sort by
* @param b the array to re-arrange based on the sort order of the
* first array.
* @param length the array range length to sort over
*/
public static final void sort(int[] a, double[] b, int length) {
mergesort(a, b, 0, length - 1);
}
/**
* Sort two arrays simultaneously, using the sort order of the values
* in the first array to determine the sort order for both arrays.
* @param a the array to sort by
* @param b the array to re-arrange based on the sort order of the
* first array.
* @param begin the start index of the range to sort
* @param end the end index, exclusive, of the range to sort
*/
public static final void sort(int[] a, double[] b, int begin, int end) {
mergesort(a, b, begin, end - 1);
}
// -- Insertion Sort --
protected static final void insertionsort(int[] a, double[] b, int p, int r) {
for (int j = p + 1; j <= r; ++j) {
int key = a[j];
double val = b[j];
int i = j - 1;
while (i >= p && a[i] > key) {
a[i + 1] = a[i];
b[i + 1] = b[i];
i--;
}
a[i + 1] = key;
b[i + 1] = val;
}
}
// -- Mergesort --
protected static final void mergesort(int[] a, double[] b, int p, int r) {
if (p >= r) {
return;
}
if (r - p + 1 < SORT_THRESHOLD) {
insertionsort(a, b, p, r);
} else {
int q = (p + r) / 2;
mergesort(a, b, p, q);
mergesort(a, b, q + 1, r);
merge(a, b, p, q, r);
}
}
protected static final void merge(int[] a, double[] b, int p, int q, int r) {
int[] t = new int[r - p + 1];
double[] v = new double[r - p + 1];
int i, p1 = p, p2 = q + 1;
for (i = 0; p1 <= q && p2 <= r; ++i) {
if (a[p1] < a[p2]) {
v[i] = b[p1];
t[i] = a[p1++];
} else {
v[i] = b[p2];
t[i] = a[p2++];
}
}
for (; p1 <= q; ++p1, ++i) {
v[i] = b[p1];
t[i] = a[p1];
}
for (; p2 <= r; ++p2, ++i) {
v[i] = b[p2];
t[i] = a[p2];
}
for (i = 0, p1 = p; i < t.length; ++i, ++p1) {
b[p1] = v[i];
a[p1] = t[i];
}
}
// -- int / int sorting ---------------------------------------------
/**
* Sort two arrays simultaneously, using the sort order of the values
* in the first array to determine the sort order for both arrays.
* @param a the array to sort by
* @param b the array to re-arrange based on the sort order of the
* first array.
*/
public static final void sort(int[] a, int[] b) {
mergesort(a, b, 0, a.length - 1);
}
/**
* Sort two arrays simultaneously, using the sort order of the values
* in the first array to determine the sort order for both arrays.
* @param a the array to sort by
* @param b the array to re-arrange based on the sort order of the
* first array.
* @param length the array range length to sort over
*/
public static final void sort(int[] a, int[] b, int length) {
mergesort(a, b, 0, length - 1);
}
/**
* Sort two arrays simultaneously, using the sort order of the values
* in the first array to determine the sort order for both arrays.
* @param a the array to sort by
* @param b the array to re-arrange based on the sort order of the
* first array.
* @param begin the start index of the range to sort
* @param end the end index, exclusive, of the range to sort
*/
public static final void sort(int[] a, int[] b, int begin, int end) {
mergesort(a, b, begin, end - 1);
}
// -- Insertion Sort --
protected static final void insertionsort(int[] a, int[] b, int p, int r) {
for (int j = p + 1; j <= r; ++j) {
int key = a[j];
int val = b[j];
int i = j - 1;
while (i >= p && a[i] > key) {
a[i + 1] = a[i];
b[i + 1] = b[i];
i--;
}
a[i + 1] = key;
b[i + 1] = val;
}
}
// -- Mergesort --
protected static final void mergesort(int[] a, int[] b, int p, int r) {
if (p >= r) {
return;
}
if (r - p + 1 < SORT_THRESHOLD) {
insertionsort(a, b, p, r);
} else {
int q = (p + r) / 2;
mergesort(a, b, p, q);
mergesort(a, b, q + 1, r);
merge(a, b, p, q, r);
}
}
protected static final void merge(int[] a, int[] b, int p, int q, int r) {
int[] t = new int[r - p + 1];
int[] v = new int[r - p + 1];
int i, p1 = p, p2 = q + 1;
for (i = 0; p1 <= q && p2 <= r; ++i) {
if (a[p1] < a[p2]) {
v[i] = b[p1];
t[i] = a[p1++];
} else {
v[i] = b[p2];
t[i] = a[p2++];
}
}
for (; p1 <= q; ++p1, ++i) {
v[i] = b[p1];
t[i] = a[p1];
}
for (; p2 <= r; ++p2, ++i) {
v[i] = b[p2];
t[i] = a[p2];
}
for (i = 0, p1 = p; i < t.length; ++i, ++p1) {
b[p1] = v[i];
a[p1] = t[i];
}
}
// -- int / Object sorting ---------------------------------------------
/**
* Sort two arrays simultaneously, using the sort order of the values
* in the first array to determine the sort order for both arrays.
* @param a the array to sort by
* @param b the array to re-arrange based on the sort order of the
* first array.
* @param begin the start index of the range to sort
* @param end the end index, exclusive, of the range to sort
*/
public static final void sort(int[] a, Object[] b, int begin, int end) {
int length = end-begin;
if ( length < SORT_THRESHOLD ) {
insertionsort(a, b, begin, end-1);
return;
}
// allocate source arrays
int[] ks = new int[length];
Object[] vs = new Object[length];
for ( int i=0, idx=begin; i<length; ++i, ++idx ) {
ks[i] = a[idx];
vs[i] = b[idx];
}
mergesort(ks, a, vs, b, begin, end, -begin);
}
/**
* Sort two arrays simultaneously, using the sort order of the values
* in the first array to determine the sort order for both arrays.
* @param a the array to sort by
* @param b the array to re-arrange based on the sort order of the
* first array.
* @param abuf a buffer array to perform the sorting without
* allocating any additional memory
* @param bbuf a buffer array to perform the sorting without
* allocating any additional memory
* @param begin the start index of the range to sort
* @param end the end index, exclusive, of the range to sort
*/
public static final void sort(int[] a, Object[] b,
int[] abuf, Object[] bbuf, int begin, int end)
{
int length = end-begin;
if ( length < SORT_THRESHOLD ) {
insertionsort(a, b, begin, end-1);
return;
}
// allocate source arrays
for ( int i=0, idx=begin; i<length; ++i, ++idx ) {
abuf[i] = a[idx];
bbuf[i] = b[idx];
}
mergesort(abuf, a, bbuf, b, begin, end, -begin);
}
// -- Insertion Sort --
protected static final void insertionsort(int[] a, Object[] b, int p, int r) {
int i, key;
Object val;
for (int j = p + 1; j <= r; ++j) {
key = a[j];
val = b[j];
i = j - 1;
while (i >= p && a[i] > key) {
a[i + 1] = a[i];
b[i + 1] = b[i];
i--;
}
a[i + 1] = key;
b[i + 1] = val;
}
}
// -- Mergesort --
protected static void mergesort(int ks[], int kd[], Object[] vs,
Object[] vd, int lo, int hi, int off)
{
int length = hi-lo;
if (length < SORT_THRESHOLD) {
insertionsort(kd, vd, lo, hi-1);
return;
}
// Recursively sort halves of dest into src
int dlo = lo;
int dhi = hi;
lo += off;
hi += off;
int mid = (lo + hi) >> 1;
mergesort(kd, ks, vd, vs, lo, mid, -off);
mergesort(kd, ks, vd, vs, mid, hi, -off);
// If list is already sorted, just copy from src to dest. This is an
// optimization that results in faster sorts for nearly ordered lists.
if ( ks[mid-1] <= ks[mid] ) {
System.arraycopy(ks, lo, kd, dlo, length);
System.arraycopy(vs, lo, vd, dlo, length);
return;
}
// Merge sorted halves (now in src) into dest
for (int i = dlo, p = lo, q = mid; i < dhi; i++) {
if (q >= hi || p < mid && ks[p] <= ks[q] ) {
vd[i] = vs[p];
kd[i] = ks[p++];
} else {
vd[i] = vs[q];
kd[i] = ks[q++];
}
}
}
protected static final void merge(int[] a, Object[] b, int p, int q, int r) {
int[] t = new int[r - p + 1];
Object[] v = new Object[r - p + 1];
int i, p1 = p, p2 = q + 1;
for (i = 0; p1 <= q && p2 <= r; ++i) {
if (a[p1] < a[p2]) {
v[i] = b[p1];
t[i] = a[p1++];
} else {
v[i] = b[p2];
t[i] = a[p2++];
}
}
for (; p1 <= q; ++p1, ++i) {
v[i] = b[p1];
t[i] = a[p1];
}
for (; p2 <= r; ++p2, ++i) {
v[i] = b[p2];
t[i] = a[p2];
}
for (i = 0, p1 = p; i < t.length; ++i, ++p1) {
b[p1] = v[i];
a[p1] = t[i];
}
}
// -- double / int sorting -------------------------------------------
/**
* Sort two arrays simultaneously, using the sort order of the values
* in the first array to determine the sort order for both arrays.
* @param a the array to sort by
* @param b the array to re-arrange based on the sort order of the
* first array.
*/
public static final void sort(double[] a, int[] b) {
mergesort(a, b, 0, a.length - 1);
}
/**
* Sort two arrays simultaneously, using the sort order of the values
* in the first array to determine the sort order for both arrays.
* @param a the array to sort by
* @param b the array to re-arrange based on the sort order of the
* first array.
* @param length the length of the range to be sorted
*/
public static final void sort(double[] a, int[] b, int length) {
mergesort(a, b, 0, length - 1);
}
/**
* Sort two arrays simultaneously, using the sort order of the values
* in the first array to determine the sort order for both arrays.
* @param a the array to sort by
* @param b the array to re-arrange based on the sort order of the
* first array.
* @param begin the start index of the range to sort
* @param end the end index, exclusive, of the range to sort
*/
public static final void sort(double[] a, int[] b, int begin, int end) {
mergesort(a, b, begin, end - 1);
}
// -- Insertion Sort --
protected static final void insertionsort(double[] a, int[] b, int p, int r) {
for (int j = p + 1; j <= r; ++j) {
double key = a[j];
int val = b[j];
int i = j - 1;
while (i >= p && a[i] > key) {
a[i + 1] = a[i];
b[i + 1] = b[i];
--i;
}
a[i + 1] = key;
b[i + 1] = val;
}
}
// -- Mergesort --
protected static final void mergesort(double[] a, int[] b, int p, int r) {
if (p >= r) {
return;
}
if (r - p + 1 < SORT_THRESHOLD) {
insertionsort(a, b, p, r);
} else {
int q = (p + r) / 2;
mergesort(a, b, p, q);
mergesort(a, b, q + 1, r);
merge(a, b, p, q, r);
}
}
protected static final void merge(double[] a, int[] b, int p, int q, int r) {
double[] t = new double[r - p + 1];
int[] v = new int[r - p + 1];
int i, p1 = p, p2 = q + 1;
for (i = 0; p1 <= q && p2 <= r; ++i) {
if (a[p1] < a[p2]) {
v[i] = b[p1];
t[i] = a[p1++];
} else {
v[i] = b[p2];
t[i] = a[p2++];
}
}
for (; p1 <= q; ++p1, ++i) {
v[i] = b[p1];
t[i] = a[p1];
}
for (; p2 <= r; ++p2, ++i) {
v[i] = b[p2];
t[i] = a[p2];
}
for (i = 0, p1 = p; i < t.length; i++, p1++) {
b[p1] = v[i];
a[p1] = t[i];
}
}
// -- float / int sorting -------------------------------------------
/**
* Sort two arrays simultaneously, using the sort order of the values
* in the first array to determine the sort order for both arrays.
* @param a the array to sort by
* @param b the array to re-arrange based on the sort order of the
* first array.
*/
public static final void sort(float[] a, int[] b) {
mergesort(a, b, 0, a.length - 1);
}
/**
* Sort two arrays simultaneously, using the sort order of the values
* in the first array to determine the sort order for both arrays.
* @param a the array to sort by
* @param b the array to re-arrange based on the sort order of the
* first array.
* @param length the length of the range to be sorted
*/
public static final void sort(float[] a, int[] b, int length) {
mergesort(a, b, 0, length - 1);
}
/**
* Sort two arrays simultaneously, using the sort order of the values
* in the first array to determine the sort order for both arrays.
* @param a the array to sort by
* @param b the array to re-arrange based on the sort order of the
* first array.
* @param begin the start index of the range to sort
* @param end the end index, exclusive, of the range to sort
*/
public static final void sort(float[] a, int[] b, int begin, int end) {
mergesort(a, b, begin, end - 1);
}
// -- Insertion Sort --
protected static final void insertionsort(float[] a, int[] b, int p, int r) {
for (int j = p + 1; j <= r; ++j) {
float key = a[j];
int val = b[j];
int i = j - 1;
while (i >= p && a[i] > key) {
a[i + 1] = a[i];
b[i + 1] = b[i];
--i;
}
a[i + 1] = key;
b[i + 1] = val;
}
}
// -- Mergesort --
protected static final void mergesort(float[] a, int[] b, int p, int r) {
if (p >= r) {
return;
}
if (r - p + 1 < SORT_THRESHOLD) {
insertionsort(a, b, p, r);
} else {
int q = (p + r) / 2;
mergesort(a, b, p, q);
mergesort(a, b, q + 1, r);
merge(a, b, p, q, r);
}
}
protected static final void merge(float[] a, int[] b, int p, int q, int r) {
float[] t = new float[r - p + 1];
int[] v = new int[r - p + 1];
int i, p1 = p, p2 = q + 1;
for (i = 0; p1 <= q && p2 <= r; ++i) {
if (a[p1] < a[p2]) {
v[i] = b[p1];
t[i] = a[p1++];
} else {
v[i] = b[p2];
t[i] = a[p2++];
}
}
for (; p1 <= q; ++p1, ++i) {
v[i] = b[p1];
t[i] = a[p1];
}
for (; p2 <= r; ++p2, ++i) {
v[i] = b[p2];
t[i] = a[p2];
}
for (i = 0, p1 = p; i < t.length; i++, p1++) {
b[p1] = v[i];
a[p1] = t[i];
}
}
// -- Object / int sorting ------------------------------------------------
/**
* Sort two arrays simultaneously, using the sort order of the values
* in the first array to determine the sort order for both arrays.
* @param a the array to sort by
* @param b the array to re-arrange based on the sort order of the
* first array.
* @param cmp the comparator to use to compare key values
*/
public static final void sort(Object[] a, int[] b, Comparator cmp) {
mergesort(a, b, 0, a.length - 1, cmp);
}
/**
* Sort two arrays simultaneously, using the sort order of the values
* in the first array to determine the sort order for both arrays.
* @param a the array to sort by
* @param b the array to re-arrange based on the sort order of the
* first array.
* @param length the length of the range to be sorted
* @param cmp the comparator to use to compare key values
*/
public static final void sort(Object[] a, int[] b, int length,
Comparator cmp)
{
mergesort(a, b, 0, length - 1, cmp);
}
/**
* Sort two arrays simultaneously, using the sort order of the values
* in the first array to determine the sort order for both arrays.
* @param a the array to sort by
* @param b the array to re-arrange based on the sort order of the
* first array.
* @param begin the start index of the range to sort
* @param end the end index, exclusive, of the range to sort
* @param cmp the comparator to use to compare key values
*/
public static final void sort(Object[] a, int[] b, int begin, int end,
Comparator cmp)
{
mergesort(a, b, begin, end - 1, cmp);
}
// -- Insertion Sort --
protected static final void insertionsort(Object[] a, int[] b, int p, int r,
Comparator cmp)
{
for (int j = p + 1; j <= r; ++j) {
Object key = a[j];
int val = b[j];
int i = j - 1;
while (i >= p && cmp.compare(a[i],key) > 0 ) {
a[i + 1] = a[i];
b[i + 1] = b[i];
--i;
}
a[i + 1] = key;
b[i + 1] = val;
}
}
// -- Mergesort --
protected static final void mergesort(Object[] a, int[] b, int p, int r,
Comparator cmp)
{
if (p >= r) {
return;
}
if (r - p + 1 < SORT_THRESHOLD) {
insertionsort(a, b, p, r, cmp);
} else {
int q = (p + r) / 2;
mergesort(a, b, p, q, cmp);
mergesort(a, b, q + 1, r, cmp);
merge(a, b, p, q, r, cmp);
}
}
protected static final void merge(Object[] a, int[] b, int p, int q, int r,
Comparator cmp)
{
Object[] t = new Object[r - p + 1];
int[] v = new int[r - p + 1];
int i, p1 = p, p2 = q + 1;
for (i = 0; p1 <= q && p2 <= r; ++i) {
if ( cmp.compare(a[p1],a[p2]) < 0 ) {
v[i] = b[p1];
t[i] = a[p1++];
} else {
v[i] = b[p2];
t[i] = a[p2++];
}
}
for (; p1 <= q; ++p1, ++i) {
v[i] = b[p1];
t[i] = a[p1];
}
for (; p2 <= r; ++p2, ++i) {
v[i] = b[p2];
t[i] = a[p2];
}
for (i = 0, p1 = p; i < t.length; i++, p1++) {
b[p1] = v[i];
a[p1] = t[i];
}
}
// ------------------------------------------------------------------------
// Array File I/O
/**
* Read in a text file as an array of integers. Uses the default java
* StringTokenizer to segment the text file. Additionally, tokens beginning
* with the '#' character are ignored.
* @param filename the name of the file to read in
* @return an array of integers parsed from the file
*/
public static int[] getIntArray(String filename) {
int[] array = null;
try {
BufferedReader br = new BufferedReader(new FileReader(filename));
String line = br.readLine();
StringTokenizer st = new StringTokenizer(line);
int maxlen = st.countTokens();
int len = 0;
array = new int[maxlen];
while ( st.hasMoreTokens() ) {
String tok = st.nextToken();
if ( tok.startsWith("#") ) // commented int
continue;
array[len++] = Integer.parseInt(tok);
}
if ( len != maxlen )
array = ArrayLib.trim(array, len);
return array;
} catch ( Exception e ) {
e.printStackTrace();
return null;
}
}
} // end of class ArrayLib