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)
54 return ascending ? Float.compare(values[o1], values[o2])
55 : Float.compare(values[o2], values[o1]);
60 * A comparator that compares two integers by comparing their respective
61 * indexed values in an array of doubles
63 static class DoubleComparator implements Comparator<Integer>
65 private final double[] values;
67 private boolean ascending;
69 DoubleComparator(double[] v, boolean asc)
76 public int compare(Integer o1, Integer o2)
80 return Double.compare(values[o1], values[o2]);
84 return Double.compare(values[o2], values[o1]);
90 * A comparator that compares two integers by comparing their respective
91 * indexed values in an array of ints
93 static class IntComparator implements Comparator<Integer>
95 private final int[] values;
97 private boolean ascending;
99 IntComparator(int[] v, boolean asc)
106 public int compare(Integer o1, Integer o2)
108 return ascending ? Integer.compare(values[o1], values[o2])
109 : Integer.compare(values[o2], values[o1]);
114 * A comparator that compares two integers by comparing their respective
115 * indexed values in an array of comparable objects.
117 static class ExternalComparator implements Comparator<Integer>
119 private final Comparable[] values;
121 private boolean ascending;
123 ExternalComparator(Comparable[] v, boolean asc)
130 public int compare(Integer o1, Integer o2)
132 return ascending ? values[o1].compareTo(values[o2])
133 : values[o2].compareTo(values[o1]);
138 * Sorts both arrays with respect to ascending order of the items in the first
144 public static void sort(int[] arr, Object[] s)
146 sort(arr, 0, arr.length - 1, s);
150 * Sorts both arrays with respect to ascending order of the items in the first
156 public static void sort(float[] arr, Object[] s)
158 sort(arr, 0, arr.length - 1, s);
162 * Sorts both arrays with respect to ascending order of the items in the first
168 public static void sort(double[] arr, Object[] s)
170 sort(arr, 0, arr.length - 1, s);
174 * Sorts both arrays with respect to descending order of the items in the
175 * first array. The sorting is case-sensitive.
180 public static void sort(String[] arr, Object[] s)
182 stringSort(arr, 0, arr.length - 1, s);
185 static void stringSort(String[] arr, int p, int r, Object[] s)
191 q = stringPartition(arr, p, r, s);
192 stringSort(arr, p, q, s);
193 stringSort(arr, q + 1, r, s);
197 static void sort(float[] arr, int p, int r, Object[] s)
203 q = partition(arr, p, r, s);
205 sort(arr, q + 1, r, s);
209 static void sort(double[] arr, int p, int r, Object[] s)
215 q = partition(arr, p, r, s);
217 sort(arr, q + 1, r, s);
221 static void sort(int[] arr, int p, int r, Object[] s)
227 q = partition(arr, p, r, s);
229 sort(arr, q + 1, r, s);
233 static int partition(float[] arr, int p, int r, Object[] s)
244 } while (arr[j] > x);
249 } while (arr[i] < x);
268 static int partition(float[] arr, int p, int r, char[] s)
279 } while (arr[j] > x);
284 } while (arr[i] < x);
303 static int partition(int[] arr, int p, int r, Object[] s)
314 } while (arr[j] > x);
319 } while (arr[i] < x);
338 static int partition(double[] arr, int p, int r, Object[] s)
349 } while (arr[j] > x);
354 } while (arr[i] < x);
373 static int stringPartition(String[] arr, int p, int r, Object[] s)
384 } while (arr[j].compareTo(x) < 0);
389 } while (arr[i].compareTo(x) > 0);
409 * Sorts both arrays to give ascending order by the first array, by first
410 * partitioning into zero and non-zero values before sorting the latter. This
411 * is faster than a direct call to charSortByFloat in the case where most of
412 * the array to be sorted is zero.
417 public static void sort(float[] arr, char[] s)
420 * Move all zero values to the front, non-zero to the back, while counting
423 float[] f1 = new float[arr.length];
424 char[] s1 = new char[s.length];
425 int negativeCount = 0;
427 int nextNonZeroValue = arr.length - 1;
428 for (int i = 0; i < arr.length; i++)
433 f1[nextNonZeroValue] = val;
434 s1[nextNonZeroValue] = s[i];
443 f1[zerosCount] = val;
444 s1[zerosCount] = s[i];
448 int positiveCount = arr.length - zerosCount - negativeCount;
450 if (zerosCount == arr.length)
456 * sort the non-zero values
458 float[] nonZeroFloats = Arrays.copyOfRange(f1, zerosCount, f1.length);
459 char[] nonZeroChars = Arrays.copyOfRange(s1, zerosCount, s1.length);
460 charSortByFloat(nonZeroFloats, nonZeroChars, true);
463 * Backfill zero values to original arrays, after the space reserved for
466 System.arraycopy(f1, 0, arr, negativeCount, zerosCount);
467 System.arraycopy(s1, 0, s, negativeCount, zerosCount);
470 * Copy sorted negative values to the front of arr, s
472 System.arraycopy(nonZeroFloats, 0, arr, 0, negativeCount);
473 System.arraycopy(nonZeroChars, 0, s, 0, negativeCount);
476 * Copy sorted positive values after the negatives and zeros
478 System.arraycopy(nonZeroFloats, negativeCount, arr,
479 negativeCount + zerosCount, positiveCount);
480 System.arraycopy(nonZeroChars, negativeCount, s,
481 negativeCount + zerosCount, positiveCount);
485 * Sorts arrays of float and char by the float values, by making an array of
486 * indices, and sorting it using a comparator that refers to the float values.
489 * ://stackoverflow.com/questions/4859261/get-the-indices-of-an-array-
495 public static void charSortByFloat(float[] arr, char[] s,
498 final int length = arr.length;
499 Integer[] indices = makeIndexArray(length);
500 Arrays.sort(indices, new FloatComparator(arr, ascending));
503 * Copy the array values as per the sorted indices
505 float[] sortedFloats = new float[length];
506 char[] sortedChars = new char[s.length];
507 for (int i = 0; i < length; i++)
509 sortedFloats[i] = arr[indices[i]];
510 sortedChars[i] = s[indices[i]];
514 * And copy the sorted values back into the arrays
516 System.arraycopy(sortedFloats, 0, arr, 0, length);
517 System.arraycopy(sortedChars, 0, s, 0, s.length);
521 * Make an array whose values are 0...length.
526 protected static Integer[] makeIndexArray(final int length)
528 Integer[] indices = new Integer[length];
529 for (int i = 0; i < length; i++)
536 static void sort(float[] arr, int p, int r, char[] s)
541 q = partition(arr, p, r, s);
543 sort(arr, q + 1, r, s);
548 * Sorts both arrays to give ascending order in the first array, by first
549 * partitioning into zero and non-zero values before sorting the latter. This
550 * is faster than a direct call to charSortByInt in the case where most of the
551 * array to be sorted is zero.
556 public static void sort(int[] arr, char[] s)
558 * Move all zero values to the front, non-zero to the back, while counting
561 int[] f1 = new int[arr.length];
562 char[] s1 = new char[s.length];
563 int negativeCount = 0;
565 int nextNonZeroValue = arr.length - 1;
566 for (int i = 0; i < arr.length; i++)
571 f1[nextNonZeroValue] = val;
572 s1[nextNonZeroValue] = s[i];
581 f1[zerosCount] = val;
582 s1[zerosCount] = s[i];
586 int positiveCount = arr.length - zerosCount - negativeCount;
588 if (zerosCount == arr.length)
594 * sort the non-zero values
596 int[] nonZeroInts = Arrays.copyOfRange(f1, zerosCount, f1.length);
597 char[] nonZeroChars = Arrays.copyOfRange(s1, zerosCount, s1.length);
598 charSortByInt(nonZeroInts, nonZeroChars, true);
601 * Backfill zero values to original arrays, after the space reserved for
604 System.arraycopy(f1, 0, arr, negativeCount, zerosCount);
605 System.arraycopy(s1, 0, s, negativeCount, zerosCount);
608 * Copy sorted negative values to the front of arr, s
610 System.arraycopy(nonZeroInts, 0, arr, 0, negativeCount);
611 System.arraycopy(nonZeroChars, 0, s, 0, negativeCount);
614 * Copy sorted positive values after the negatives and zeros
616 System.arraycopy(nonZeroInts, negativeCount, arr,
617 negativeCount + zerosCount, positiveCount);
618 System.arraycopy(nonZeroChars, negativeCount, s,
619 negativeCount + zerosCount, positiveCount);
623 * Sorts arrays of int and char, by making an array of indices, and sorting it
624 * using a comparator that refers to the int values.
627 * ://stackoverflow.com/questions/4859261/get-the-indices-of-an-array-
633 public static void charSortByInt(int[] arr, char[] s, boolean ascending)
635 final int length = arr.length;
636 Integer[] indices = makeIndexArray(length);
637 Arrays.sort(indices, new IntComparator(arr, ascending));
640 * Copy the array values as per the sorted indices
642 int[] sortedInts = new int[length];
643 char[] sortedChars = new char[s.length];
644 for (int i = 0; i < length; i++)
646 sortedInts[i] = arr[indices[i]];
647 sortedChars[i] = s[indices[i]];
651 * And copy the sorted values back into the arrays
653 System.arraycopy(sortedInts, 0, arr, 0, length);
654 System.arraycopy(sortedChars, 0, s, 0, s.length);
658 * Sorts arrays of int and Object, by making an array of indices, and sorting
659 * it using a comparator that refers to the int values.
662 * ://stackoverflow.com/questions/4859261/get-the-indices-of-an-array-
668 public static void sortByInt(int[] arr, Object[] s, boolean ascending)
670 final int length = arr.length;
671 Integer[] indices = makeIndexArray(length);
672 Arrays.sort(indices, new IntComparator(arr, ascending));
675 * Copy the array values as per the sorted indices
677 int[] sortedInts = new int[length];
678 Object[] sortedObjects = new Object[s.length];
679 for (int i = 0; i < length; i++)
681 sortedInts[i] = arr[indices[i]];
682 sortedObjects[i] = s[indices[i]];
686 * And copy the sorted values back into the arrays
688 System.arraycopy(sortedInts, 0, arr, 0, length);
689 System.arraycopy(sortedObjects, 0, s, 0, s.length);
693 * Sorts arrays of String and Object, by making an array of indices, and
694 * sorting it using a comparator that refers to the String values. Both arrays
695 * are sorted by case-sensitive order of the string array values.
698 * ://stackoverflow.com/questions/4859261/get-the-indices-of-an-array-
704 public static void sortByString(String[] arr, Object[] s,
707 final int length = arr.length;
708 Integer[] indices = makeIndexArray(length);
709 Arrays.sort(indices, new ExternalComparator(arr, ascending));
712 * Copy the array values as per the sorted indices
714 String[] sortedStrings = new String[length];
715 Object[] sortedObjects = new Object[s.length];
716 for (int i = 0; i < length; i++)
718 sortedStrings[i] = arr[indices[i]];
719 sortedObjects[i] = s[indices[i]];
723 * And copy the sorted values back into the arrays
725 System.arraycopy(sortedStrings, 0, arr, 0, length);
726 System.arraycopy(sortedObjects, 0, s, 0, s.length);
730 * Sorts arrays of double and Object, by making an array of indices, and
731 * sorting it using a comparator that refers to the double values.
734 * ://stackoverflow.com/questions/4859261/get-the-indices-of-an-array-
740 public static void sortByDouble(double[] arr, Object[] s,
743 final int length = arr.length;
744 Integer[] indices = makeIndexArray(length);
745 Arrays.sort(indices, new DoubleComparator(arr, ascending));
748 * Copy the array values as per the sorted indices
750 double[] sortedDoubles = new double[length];
751 Object[] sortedObjects = new Object[s.length];
752 for (int i = 0; i < length; i++)
754 sortedDoubles[i] = arr[indices[i]];
755 sortedObjects[i] = s[indices[i]];
759 * And copy the sorted values back into the arrays
761 System.arraycopy(sortedDoubles, 0, arr, 0, length);
762 System.arraycopy(sortedObjects, 0, s, 0, s.length);