2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import java.util.Arrays;
24 import java.util.Comparator;
27 * A class to perform efficient sorting of arrays of objects based on arrays of
28 * scores or other attributes. For example, residues by percentage frequency.
33 public class QuickSort
36 * A comparator that compares two integers by comparing their respective
37 * indexed values in an array of floats
39 static class FloatComparator implements Comparator<Integer>
41 private final float[] values;
43 private boolean ascending;
45 FloatComparator(float[] v, boolean asc)
52 public int compare(Integer o1, Integer o2)
55 ? Float.compare(values[o1.intValue()], values[o2.intValue()])
56 : Float.compare(values[o2.intValue()], values[o1.intValue()]);
61 * A comparator that compares two integers by comparing their respective
62 * indexed values in an array of doubles
64 static class DoubleComparator implements Comparator<Integer>
66 private final double[] values;
68 private boolean ascending;
70 DoubleComparator(double[] v, boolean asc)
77 public int compare(Integer o1, Integer o2)
81 return Double.compare(values[o1.intValue()], values[o2.intValue()]);
85 return Double.compare(values[o2.intValue()], values[o1.intValue()]);
91 * A comparator that compares two integers by comparing their respective
92 * indexed values in an array of ints
94 static class IntComparator implements Comparator<Integer>
96 private final int[] values;
98 private boolean ascending;
100 IntComparator(int[] v, boolean asc)
107 public int compare(Integer o1, Integer o2)
110 ? Integer.compare(values[o1.intValue()],
111 values[o2.intValue()])
112 : Integer.compare(values[o2.intValue()],
113 values[o1.intValue()]);
118 * A comparator that compares two integers by comparing their respective
119 * indexed values in an array of comparable objects.
121 static class ExternalComparator implements Comparator<Integer>
123 private final Comparable[] values;
125 private boolean ascending;
127 ExternalComparator(Comparable[] v, boolean asc)
134 public int compare(Integer o1, Integer o2)
137 ? values[o1.intValue()].compareTo(values[o2.intValue()])
138 : values[o2.intValue()].compareTo(values[o1.intValue()]);
143 * Sorts both arrays with respect to ascending order of the items in the first
149 public static void sort(int[] arr, Object[] s)
151 sort(arr, 0, arr.length - 1, s);
155 * Sorts both arrays with respect to ascending order of the items in the first
161 public static void sort(float[] arr, Object[] s)
163 sort(arr, 0, arr.length - 1, s);
167 * Sorts both arrays with respect to ascending order of the items in the first
173 public static void sort(double[] arr, Object[] s)
175 sort(arr, 0, arr.length - 1, s);
179 * Sorts both arrays with respect to descending order of the items in the
180 * first array. The sorting is case-sensitive.
185 public static void sort(String[] arr, Object[] s)
187 stringSort(arr, 0, arr.length - 1, s);
190 static void stringSort(String[] arr, int p, int r, Object[] s)
196 q = stringPartition(arr, p, r, s);
197 stringSort(arr, p, q, s);
198 stringSort(arr, q + 1, r, s);
202 static void sort(float[] arr, int p, int r, Object[] s)
208 q = partition(arr, p, r, s);
210 sort(arr, q + 1, r, s);
214 static void sort(double[] arr, int p, int r, Object[] s)
220 q = partition(arr, p, r, s);
222 sort(arr, q + 1, r, s);
226 static void sort(int[] arr, int p, int r, Object[] s)
232 q = partition(arr, p, r, s);
234 sort(arr, q + 1, r, s);
238 static int partition(float[] arr, int p, int r, Object[] s)
249 } while (arr[j] > x);
254 } while (arr[i] < x);
273 static int partition(float[] arr, int p, int r, char[] s)
284 } while (arr[j] > x);
289 } while (arr[i] < x);
308 static int partition(int[] arr, int p, int r, Object[] s)
319 } while (arr[j] > x);
324 } while (arr[i] < x);
343 static int partition(double[] arr, int p, int r, Object[] s)
354 } while (arr[j] > x);
359 } while (arr[i] < x);
378 static int stringPartition(String[] arr, int p, int r, Object[] s)
389 } while (arr[j].compareTo(x) < 0);
394 } while (arr[i].compareTo(x) > 0);
414 * Sorts both arrays to give ascending order by the first array, by first
415 * partitioning into zero and non-zero values before sorting the latter. This
416 * is faster than a direct call to charSortByFloat in the case where most of
417 * the array to be sorted is zero.
422 public static void sort(float[] arr, char[] s)
425 * Move all zero values to the front, non-zero to the back, while counting
428 float[] f1 = new float[arr.length];
429 char[] s1 = new char[s.length];
430 int negativeCount = 0;
432 int nextNonZeroValue = arr.length - 1;
433 for (int i = 0; i < arr.length; i++)
438 f1[nextNonZeroValue] = val;
439 s1[nextNonZeroValue] = s[i];
448 f1[zerosCount] = val;
449 s1[zerosCount] = s[i];
453 int positiveCount = arr.length - zerosCount - negativeCount;
455 if (zerosCount == arr.length)
461 * sort the non-zero values
463 float[] nonZeroFloats = Arrays.copyOfRange(f1, zerosCount, f1.length);
464 char[] nonZeroChars = Arrays.copyOfRange(s1, zerosCount, s1.length);
465 charSortByFloat(nonZeroFloats, nonZeroChars, true);
468 * Backfill zero values to original arrays, after the space reserved for
471 System.arraycopy(f1, 0, arr, negativeCount, zerosCount);
472 System.arraycopy(s1, 0, s, negativeCount, zerosCount);
475 * Copy sorted negative values to the front of arr, s
477 System.arraycopy(nonZeroFloats, 0, arr, 0, negativeCount);
478 System.arraycopy(nonZeroChars, 0, s, 0, negativeCount);
481 * Copy sorted positive values after the negatives and zeros
483 System.arraycopy(nonZeroFloats, negativeCount, arr,
484 negativeCount + zerosCount, positiveCount);
485 System.arraycopy(nonZeroChars, negativeCount, s,
486 negativeCount + zerosCount, positiveCount);
490 * Sorts arrays of float and char by the float values, by making an array of
491 * indices, and sorting it using a comparator that refers to the float values.
494 * ://stackoverflow.com/questions/4859261/get-the-indices-of-an-array-
500 public static void charSortByFloat(float[] arr, char[] s,
503 final int length = arr.length;
504 Integer[] indices = makeIndexArray(length);
505 Arrays.sort(indices, new FloatComparator(arr, ascending));
508 * Copy the array values as per the sorted indices
510 float[] sortedFloats = new float[length];
511 char[] sortedChars = new char[s.length];
512 for (int i = 0; i < length; i++)
514 sortedFloats[i] = arr[indices[i]];
515 sortedChars[i] = s[indices[i]];
519 * And copy the sorted values back into the arrays
521 System.arraycopy(sortedFloats, 0, arr, 0, length);
522 System.arraycopy(sortedChars, 0, s, 0, s.length);
526 * Make an array whose values are 0...length.
531 protected static Integer[] makeIndexArray(final int length)
533 Integer[] indices = new Integer[length];
534 for (int i = 0; i < length; i++)
541 static void sort(float[] arr, int p, int r, char[] s)
546 q = partition(arr, p, r, s);
548 sort(arr, q + 1, r, s);
553 * Sorts both arrays to give ascending order in the first array, by first
554 * partitioning into zero and non-zero values before sorting the latter. This
555 * is faster than a direct call to charSortByInt in the case where most of the
556 * array to be sorted is zero.
561 public static void sort(int[] arr, char[] s)
563 * Move all zero values to the front, non-zero to the back, while counting
566 int[] f1 = new int[arr.length];
567 char[] s1 = new char[s.length];
568 int negativeCount = 0;
570 int nextNonZeroValue = arr.length - 1;
571 for (int i = 0; i < arr.length; i++)
576 f1[nextNonZeroValue] = val;
577 s1[nextNonZeroValue] = s[i];
586 f1[zerosCount] = val;
587 s1[zerosCount] = s[i];
591 int positiveCount = arr.length - zerosCount - negativeCount;
593 if (zerosCount == arr.length)
599 * sort the non-zero values
601 int[] nonZeroInts = Arrays.copyOfRange(f1, zerosCount, f1.length);
602 char[] nonZeroChars = Arrays.copyOfRange(s1, zerosCount, s1.length);
603 charSortByInt(nonZeroInts, nonZeroChars, true);
606 * Backfill zero values to original arrays, after the space reserved for
609 System.arraycopy(f1, 0, arr, negativeCount, zerosCount);
610 System.arraycopy(s1, 0, s, negativeCount, zerosCount);
613 * Copy sorted negative values to the front of arr, s
615 System.arraycopy(nonZeroInts, 0, arr, 0, negativeCount);
616 System.arraycopy(nonZeroChars, 0, s, 0, negativeCount);
619 * Copy sorted positive values after the negatives and zeros
621 System.arraycopy(nonZeroInts, negativeCount, arr,
622 negativeCount + zerosCount, positiveCount);
623 System.arraycopy(nonZeroChars, negativeCount, s,
624 negativeCount + zerosCount, positiveCount);
628 * Sorts arrays of int and char, by making an array of indices, and sorting it
629 * using a comparator that refers to the int values.
632 * ://stackoverflow.com/questions/4859261/get-the-indices-of-an-array-
638 public static void charSortByInt(int[] arr, char[] s, boolean ascending)
640 final int length = arr.length;
641 Integer[] indices = makeIndexArray(length);
642 Arrays.sort(indices, new IntComparator(arr, ascending));
645 * Copy the array values as per the sorted indices
647 int[] sortedInts = new int[length];
648 char[] sortedChars = new char[s.length];
649 for (int i = 0; i < length; i++)
651 sortedInts[i] = arr[indices[i]];
652 sortedChars[i] = s[indices[i]];
656 * And copy the sorted values back into the arrays
658 System.arraycopy(sortedInts, 0, arr, 0, length);
659 System.arraycopy(sortedChars, 0, s, 0, s.length);
663 * Sorts arrays of int and Object, by making an array of indices, and sorting
664 * it using a comparator that refers to the int values.
667 * ://stackoverflow.com/questions/4859261/get-the-indices-of-an-array-
673 public static void sortByInt(int[] arr, Object[] s, boolean ascending)
675 final int length = arr.length;
676 Integer[] indices = makeIndexArray(length);
677 Arrays.sort(indices, new IntComparator(arr, ascending));
680 * Copy the array values as per the sorted indices
682 int[] sortedInts = new int[length];
683 Object[] sortedObjects = new Object[s.length];
684 for (int i = 0; i < length; i++)
686 sortedInts[i] = arr[indices[i]];
687 sortedObjects[i] = s[indices[i]];
691 * And copy the sorted values back into the arrays
693 System.arraycopy(sortedInts, 0, arr, 0, length);
694 System.arraycopy(sortedObjects, 0, s, 0, s.length);
698 * Sorts arrays of String and Object, by making an array of indices, and
699 * sorting it using a comparator that refers to the String values. Both arrays
700 * are sorted by case-sensitive order of the string array values.
703 * ://stackoverflow.com/questions/4859261/get-the-indices-of-an-array-
709 public static void sortByString(String[] arr, Object[] s,
712 final int length = arr.length;
713 Integer[] indices = makeIndexArray(length);
714 Arrays.sort(indices, new ExternalComparator(arr, ascending));
717 * Copy the array values as per the sorted indices
719 String[] sortedStrings = new String[length];
720 Object[] sortedObjects = new Object[s.length];
721 for (int i = 0; i < length; i++)
723 sortedStrings[i] = arr[indices[i]];
724 sortedObjects[i] = s[indices[i]];
728 * And copy the sorted values back into the arrays
730 System.arraycopy(sortedStrings, 0, arr, 0, length);
731 System.arraycopy(sortedObjects, 0, s, 0, s.length);
735 * Sorts arrays of double and Object, by making an array of indices, and
736 * sorting it using a comparator that refers to the double values.
739 * ://stackoverflow.com/questions/4859261/get-the-indices-of-an-array-
745 public static void sortByDouble(double[] arr, Object[] s,
748 final int length = arr.length;
749 Integer[] indices = makeIndexArray(length);
750 Arrays.sort(indices, new DoubleComparator(arr, ascending));
753 * Copy the array values as per the sorted indices
755 double[] sortedDoubles = new double[length];
756 Object[] sortedObjects = new Object[s.length];
757 for (int i = 0; i < length; i++)
759 sortedDoubles[i] = arr[indices[i]];
760 sortedObjects[i] = s[indices[i]];
764 * And copy the sorted values back into the arrays
766 System.arraycopy(sortedDoubles, 0, arr, 0, length);
767 System.arraycopy(sortedObjects, 0, s, 0, s.length);