Mercurial > jhg
comparison src/org/tmatesoft/hg/internal/ArrayHelper.java @ 657:6334b0267103
ParentChildMap can supply RevisionMap. Refactor ArrayHelper to keep most of sorted/reverse index magic inside
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Thu, 04 Jul 2013 20:27:45 +0200 |
parents | b9592e21176a |
children | d10399f80f4e |
comparison
equal
deleted
inserted
replaced
656:a937e63b6e02 | 657:6334b0267103 |
---|---|
14 * the terms of a license other than GNU General Public License | 14 * the terms of a license other than GNU General Public License |
15 * contact TMate Software at support@hg4j.com | 15 * contact TMate Software at support@hg4j.com |
16 */ | 16 */ |
17 package org.tmatesoft.hg.internal; | 17 package org.tmatesoft.hg.internal; |
18 | 18 |
19 import java.util.Arrays; | |
20 | |
19 /** | 21 /** |
20 * Internal alternative to Arrays.sort to build reversed index along with sorting | 22 * Internal alternative to Arrays.sort to build reversed index along with sorting |
23 * and to perform lookup (binary search) without sorted array, using reversed index. | |
21 * | 24 * |
22 * @author Artem Tikhomirov | 25 * @author Artem Tikhomirov |
23 * @author TMate Software Ltd. | 26 * @author TMate Software Ltd. |
24 */ | 27 */ |
25 public class ArrayHelper { | 28 public final class ArrayHelper<T extends Comparable<T>> { |
26 private int[] reverse; | 29 private int[] reverse; // aka sorted2natural |
27 | 30 private final T[] data; |
28 @SuppressWarnings("unchecked") | 31 private T[] sorted; |
29 public void sort(Comparable<?>[] a) { | 32 |
30 // Object[] aux = (Object[]) a.clone(); | 33 public ArrayHelper(T[] _data) { |
31 reverse = new int[a.length]; | 34 assert _data != null; |
32 sort1((Comparable<Object>[])a, 0, a.length); | 35 data = _data; |
36 } | |
37 | |
38 /** | |
39 * Sort data this helper wraps, possibly using supplied array (optional) | |
40 * to keep sorted elements | |
41 * @param sortDest array to keep sorted values at, or <code>null</code> | |
42 * @param sortDestIsEmpty <code>false</code> when sortDest already contains copy of data to be sorted | |
43 * @param keepSorted <code>true</code> to save sorted array for future use (e.g. in | |
44 */ | |
45 public void sort(T[] sortDest, boolean sortDestIsEmpty, boolean keepSorted) { | |
46 if (sortDest != null) { | |
47 assert sortDest.length >= data.length; | |
48 if (sortDestIsEmpty) { | |
49 System.arraycopy(data, 0, sortDest, 0, data.length); | |
50 } | |
51 sorted = sortDest; | |
52 } else { | |
53 sorted = data.clone(); | |
54 } | |
55 reverse = new int[data.length]; | |
33 for (int i = 0; i < reverse.length; i++) { | 56 for (int i = 0; i < reverse.length; i++) { |
34 // element that was not moved don't have an index in reverse. | 57 // initial reverse indexes, so that elements that do |
35 // perhaps, can do it inside sort alg? | 58 // not move during sort got correct indexes |
36 // Alternatively, may start with filling reverse[] array with initial indexes and | 59 reverse[i] = i; |
37 // avoid != 0 comparisons in #swap altogether? | 60 } |
38 if (reverse[i] == 0) { | 61 sort1(0, data.length); |
39 reverse[i] = i+1; | 62 if (!keepSorted) { |
40 } | 63 sorted = null; |
41 } | 64 } |
65 } | |
66 | |
67 /** | |
68 * @return all reverse indexes | |
69 */ | |
70 public int[] getReverseIndexes() { | |
71 return reverse; | |
72 } | |
73 | |
74 public int getReverseIndex(int sortedIndex) { | |
75 return reverse[sortedIndex]; | |
76 } | |
77 | |
78 public T get(int index) { | |
79 return data[index]; | |
80 } | |
81 | |
82 public T[] getData() { | |
83 return data; | |
84 } | |
85 | |
86 /** | |
87 * Look up sorted index of the value, using sort information | |
88 * @return same value as {@link Arrays#binarySearch(Object[], Object)} does | |
89 */ | |
90 public int binarySearchSorted(T value) { | |
91 if (sorted != null) { | |
92 return Arrays.binarySearch(sorted, 0, data.length, value); | |
93 } | |
94 return binarySearchWithReverse(0, data.length, value); | |
95 } | |
96 | |
97 /** | |
98 * Look up index of the value in the original array. | |
99 * @return index in original data, or <code>defaultValue</code> if value not found | |
100 */ | |
101 public int binarySearch(T value, int defaultValue) { | |
102 int x = binarySearchSorted(value); | |
103 if (x < 0) { | |
104 return defaultValue; | |
105 } | |
106 return reverse[x]; | |
42 } | 107 } |
43 | 108 |
44 /** | 109 /** |
45 * Slightly modified version of Arrays.sort1(int[], int, int) quicksort alg (just to deal with Object[]) | 110 * Slightly modified version of Arrays.sort1(int[], int, int) quicksort alg (just to deal with Object[]) |
46 */ | 111 */ |
47 private void sort1(Comparable<Object> x[], int off, int len) { | 112 private void sort1(int off, int len) { |
113 @SuppressWarnings("unchecked") | |
114 Comparable<Object>[] x = (Comparable<Object>[]) sorted; | |
48 // Insertion sort on smallest arrays | 115 // Insertion sort on smallest arrays |
49 if (len < 7) { | 116 if (len < 7) { |
50 for (int i=off; i<len+off; i++) | 117 for (int i=off; i<len+off; i++) |
51 for (int j=i; j>off && x[j-1].compareTo(x[j]) > 0; j--) | 118 for (int j=i; j>off && x[j-1].compareTo(x[j]) > 0; j--) |
52 swap(x, j, j-1); | 119 swap(j, j-1); |
53 return; | 120 return; |
54 } | 121 } |
55 | 122 |
56 // Choose a partition element, v | 123 // Choose a partition element, v |
57 int m = off + (len >> 1); // Small arrays, middle element | 124 int m = off + (len >> 1); // Small arrays, middle element |
58 if (len > 7) { | 125 if (len > 7) { |
59 int l = off; | 126 int l = off; |
60 int n = off + len - 1; | 127 int n = off + len - 1; |
61 if (len > 40) { // Big arrays, pseudomedian of 9 | 128 if (len > 40) { // Big arrays, pseudomedian of 9 |
62 int s = len/8; | 129 int s = len/8; |
63 l = med3(x, l, l+s, l+2*s); | 130 l = med3(l, l+s, l+2*s); |
64 m = med3(x, m-s, m, m+s); | 131 m = med3(m-s, m, m+s); |
65 n = med3(x, n-2*s, n-s, n); | 132 n = med3(n-2*s, n-s, n); |
66 } | 133 } |
67 m = med3(x, l, m, n); // Mid-size, med of 3 | 134 m = med3(l, m, n); // Mid-size, med of 3 |
68 } | 135 } |
69 Comparable<Object> v = x[m]; | 136 Comparable<Object> v = x[m]; |
70 | 137 |
71 // Establish Invariant: v* (<v)* (>v)* v* | 138 // Establish Invariant: v* (<v)* (>v)* v* |
72 int a = off, b = a, c = off + len - 1, d = c; | 139 int a = off, b = a, c = off + len - 1, d = c; |
73 while(true) { | 140 while(true) { |
74 while (b <= c && x[b].compareTo(v) <= 0) { | 141 while (b <= c && x[b].compareTo(v) <= 0) { |
75 if (x[b] == v) | 142 if (x[b] == v) |
76 swap(x, a++, b); | 143 swap(a++, b); |
77 b++; | 144 b++; |
78 } | 145 } |
79 while (c >= b && x[c].compareTo(v) >= 0) { | 146 while (c >= b && x[c].compareTo(v) >= 0) { |
80 if (x[c] == v) | 147 if (x[c] == v) |
81 swap(x, c, d--); | 148 swap(c, d--); |
82 c--; | 149 c--; |
83 } | 150 } |
84 if (b > c) | 151 if (b > c) |
85 break; | 152 break; |
86 swap(x, b++, c--); | 153 swap(b++, c--); |
87 } | 154 } |
88 | 155 |
89 // Swap partition elements back to middle | 156 // Swap partition elements back to middle |
90 int s, n = off + len; | 157 int s, n = off + len; |
91 s = Math.min(a-off, b-a ); vecswap(x, off, b-s, s); | 158 s = Math.min(a-off, b-a ); vecswap(off, b-s, s); |
92 s = Math.min(d-c, n-d-1); vecswap(x, b, n-s, s); | 159 s = Math.min(d-c, n-d-1); vecswap(b, n-s, s); |
93 | 160 |
94 // Recursively sort non-partition-elements | 161 // Recursively sort non-partition-elements |
95 if ((s = b-a) > 1) | 162 if ((s = b-a) > 1) |
96 sort1(x, off, s); | 163 sort1(off, s); |
97 if ((s = d-c) > 1) | 164 if ((s = d-c) > 1) |
98 sort1(x, n-s, s); | 165 sort1(n-s, s); |
99 } | 166 } |
100 | 167 |
101 /** | 168 /** |
102 * Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)]. | 169 * Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)]. |
103 */ | 170 */ |
104 private void vecswap(Object[] x, int a, int b, int n) { | 171 private void vecswap(int a, int b, int n) { |
105 for (int i=0; i<n; i++, a++, b++) { | 172 for (int i=0; i<n; i++, a++, b++) { |
106 swap(x, a, b); | 173 swap(a, b); |
107 } | 174 } |
108 } | 175 } |
109 | 176 |
110 /** | 177 /** |
111 * Returns the index of the median of the three indexed integers. | 178 * Returns the index of the median of the three indexed integers. |
112 */ | 179 */ |
113 private static int med3(Comparable<Object>[] x, int a, int b, int c) { | 180 private int med3(int a, int b, int c) { |
114 return (x[a].compareTo(x[b]) < 0 ? | 181 @SuppressWarnings("unchecked") |
115 (x[b].compareTo(x[c]) < 0 ? b : x[a].compareTo(x[c]) < 0 ? c : a) : | 182 Comparable<Object>[] x = (Comparable<Object>[]) sorted; |
116 (x[b].compareTo(x[c]) > 0 ? b : x[a].compareTo(x[c]) > 0 ? c : a)); | 183 return (x[a].compareTo(x[b]) < 0 ? |
184 (x[b].compareTo(x[c]) < 0 ? b : x[a].compareTo(x[c]) < 0 ? c : a) : | |
185 (x[b].compareTo(x[c]) > 0 ? b : x[a].compareTo(x[c]) > 0 ? c : a)); | |
117 } | 186 } |
118 | 187 |
119 | 188 /** |
120 /** | |
121 * @return the reverse | |
122 */ | |
123 public int[] getReverse() { | |
124 return reverse; | |
125 } | |
126 | |
127 /** | |
128 * Swaps x[a] with x[b]. | 189 * Swaps x[a] with x[b]. |
129 */ | 190 */ |
130 private void swap(Object[] x, int a, int b) { | 191 private void swap(int a, int b) { |
192 Object[] x = sorted; | |
131 Object t = x[a]; | 193 Object t = x[a]; |
132 x[a] = x[b]; | 194 x[a] = x[b]; |
133 x[b] = t; | 195 x[b] = t; |
134 int z1 = reverse[a] != 0 ? reverse[a] : a+1; | 196 int z1 = reverse[a]; |
135 int z2 = reverse[b] != 0 ? reverse[b] : b+1; | 197 int z2 = reverse[b]; |
136 reverse[b] = z1; | 198 reverse[b] = z1; |
137 reverse[a] = z2; | 199 reverse[a] = z2; |
138 } | 200 } |
201 | |
202 // copied from Arrays.binarySearch0, update to be instance method and to use reverse indexes | |
203 private int binarySearchWithReverse(int fromIndex, int toIndex, T key) { | |
204 int low = fromIndex; | |
205 int high = toIndex - 1; | |
206 | |
207 while (low <= high) { | |
208 int mid = (low + high) >>> 1; | |
209 // data[reverse[x]] gives sorted value at index x | |
210 T midVal = data[reverse[mid]]; | |
211 int cmp = midVal.compareTo(key); | |
212 | |
213 if (cmp < 0) | |
214 low = mid + 1; | |
215 else if (cmp > 0) | |
216 high = mid - 1; | |
217 else | |
218 return mid; // key found | |
219 } | |
220 return -(low + 1); // key not found. | |
221 } | |
222 | |
139 } | 223 } |