Mercurial > hg4j
diff src/org/tmatesoft/hg/internal/ArrayHelper.java @ 307:2f2ab5c27f41
Collect sort reverse indexes along with array sorting
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Sat, 24 Sep 2011 04:06:27 +0200 |
parents | |
children | 237de162be28 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tmatesoft/hg/internal/ArrayHelper.java Sat Sep 24 04:06:27 2011 +0200 @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2011 TMate Software Ltd + * + * This program 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; version 2 of the License. + * + * This program 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. + * + * For information on how to redistribute this software under + * the terms of a license other than GNU General Public License + * contact TMate Software at support@hg4j.com + */ +package org.tmatesoft.hg.internal; + +/** + * + * @author Artem Tikhomirov + * @author TMate Software Ltd. + */ +public class ArrayHelper { + private int[] reverse; + + @SuppressWarnings("unchecked") + public void sort(Comparable<?>[] a) { +// Object[] aux = (Object[]) a.clone(); + reverse = new int[a.length]; + sort1((Comparable<Object>[])a, 0, a.length); + } + + private void sort1(Comparable<Object> x[], int off, int len) { + // Insertion sort on smallest arrays + if (len < 7) { + for (int i=off; i<len+off; i++) + for (int j=i; j>off && x[j-1].compareTo(x[j]) > 0; j--) + swap(x, j, j-1); + return; + } + + // Choose a partition element, v + int m = off + (len >> 1); // Small arrays, middle element + if (len > 7) { + int l = off; + int n = off + len - 1; + if (len > 40) { // Big arrays, pseudomedian of 9 + int s = len/8; + l = med3(x, l, l+s, l+2*s); + m = med3(x, m-s, m, m+s); + n = med3(x, n-2*s, n-s, n); + } + m = med3(x, l, m, n); // Mid-size, med of 3 + } + Comparable<Object> v = x[m]; + + // Establish Invariant: v* (<v)* (>v)* v* + int a = off, b = a, c = off + len - 1, d = c; + while(true) { + while (b <= c && x[b].compareTo(v) <= 0) { + if (x[b] == v) + swap(x, a++, b); + b++; + } + while (c >= b && x[c].compareTo(v) >= 0) { + if (x[c] == v) + swap(x, c, d--); + c--; + } + if (b > c) + break; + swap(x, b++, c--); + } + + // Swap partition elements back to middle + int s, n = off + len; + s = Math.min(a-off, b-a ); vecswap(x, off, b-s, s); + s = Math.min(d-c, n-d-1); vecswap(x, b, n-s, s); + + // Recursively sort non-partition-elements + if ((s = b-a) > 1) + sort1(x, off, s); + if ((s = d-c) > 1) + sort1(x, n-s, s); + } + + /** + * Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)]. + */ + private void vecswap(Object[] x, int a, int b, int n) { + for (int i=0; i<n; i++, a++, b++) { + swap(x, a, b); + } + } + + /** + * Returns the index of the median of the three indexed integers. + */ + private static int med3(Comparable<Object>[] x, int a, int b, int c) { + return (x[a].compareTo(x[b]) < 0 ? + (x[b].compareTo(x[c]) < 0 ? b : x[a].compareTo(x[c]) < 0 ? c : a) : + (x[b].compareTo(x[c]) > 0 ? b : x[a].compareTo(x[c]) > 0 ? c : a)); + } + + + /** + * @return the reverse + */ + public int[] getReverse() { + return reverse; + } + + /** + * Swaps x[a] with x[b]. + */ + private void swap(Object[] x, int a, int b) { + Object t = x[a]; + x[a] = x[b]; + x[b] = t; + int z1 = reverse[a] != 0 ? reverse[a] : a+1; + int z2 = reverse[b] != 0 ? reverse[b] : b+1; + reverse[b] = z1; + reverse[a] = z2; + } +}