Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(273)

Side by Side Diff: packages/collection/lib/src/algorithms.dart

Issue 2989763002: Update charted to 0.4.8 and roll (Closed)
Patch Set: Removed Cutch from list of reviewers Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 import "dart:math" as math;
6
7 import "utils.dart";
8
9 /// Returns a position of the [value] in [sortedList], if it is there.
10 ///
11 /// If the list isn't sorted according to the [compare] function, the result
12 /// is unpredictable.
13 ///
14 /// If [compare] is omitted, this defaults to calling [Comparable.compareTo] on
15 /// the objects. If any object is not [Comparable], this throws a [CastError].
16 ///
17 /// Returns -1 if [value] is not in the list by default.
18 int binarySearch<T>(List<T> sortedList, T value, {int compare(T a, T b)}) {
19 compare ??= defaultCompare<T>();
20 int min = 0;
21 int max = sortedList.length;
22 while (min < max) {
23 int mid = min + ((max - min) >> 1);
24 var element = sortedList[mid];
25 int comp = compare(element, value);
26 if (comp == 0) return mid;
27 if (comp < 0) {
28 min = mid + 1;
29 } else {
30 max = mid;
31 }
32 }
33 return -1;
34 }
35
36 /// Returns the first position in [sortedList] that does not compare less than
37 /// [value].
38 ///
39 /// If the list isn't sorted according to the [compare] function, the result
40 /// is unpredictable.
41 ///
42 /// If [compare] is omitted, this defaults to calling [Comparable.compareTo] on
43 /// the objects. If any object is not [Comparable], this throws a [CastError].
44 ///
45 /// Returns [sortedList.length] if all the items in [sortedList] compare less
46 /// than [value].
47 int lowerBound<T>(List<T> sortedList, T value, {int compare(T a, T b)}) {
48 compare ??= defaultCompare<T>();
49 int min = 0;
50 int max = sortedList.length;
51 while (min < max) {
52 int mid = min + ((max - min) >> 1);
53 var element = sortedList[mid];
54 int comp = compare(element, value);
55 if (comp < 0) {
56 min = mid + 1;
57 } else {
58 max = mid;
59 }
60 }
61 return min;
62 }
63
64 /// Shuffles a list randomly.
65 ///
66 /// A sub-range of a list can be shuffled by providing [start] and [end].
67 void shuffle(List list, [int start = 0, int end = null]) {
68 var random = new math.Random();
69 if (end == null) end = list.length;
70 int length = end - start;
71 while (length > 1) {
72 int pos = random.nextInt(length);
73 length--;
74 var tmp1 = list[start + pos];
75 list[start + pos] = list[start + length];
76 list[start + length] = tmp1;
77 }
78 }
79
80 /// Reverses a list, or a part of a list, in-place.
81 void reverse(List list, [int start = 0, int end = null]) {
82 if (end == null) end = list.length;
83 _reverse(list, start, end);
84 }
85
86 /// Internal helper function that assumes valid arguments.
87 void _reverse(List list, int start, int end) {
88 for (int i = start, j = end - 1; i < j; i++, j--) {
89 var tmp = list[i];
90 list[i] = list[j];
91 list[j] = tmp;
92 }
93 }
94
95 /// Sort a list between [start] (inclusive) and [end] (exclusive) using
96 /// insertion sort.
97 ///
98 /// If [compare] is omitted, this defaults to calling [Comparable.compareTo] on
99 /// the objects. If any object is not [Comparable], this throws a [CastError].
100 ///
101 /// Insertion sort is a simple sorting algorithm. For `n` elements it does on
102 /// the order of `n * log(n)` comparisons but up to `n` squared moves. The
103 /// sorting is performed in-place, without using extra memory.
104 ///
105 /// For short lists the many moves have less impact than the simple algorithm,
106 /// and it is often the favored sorting algorithm for short lists.
107 ///
108 /// This insertion sort is stable: Equal elements end up in the same order
109 /// as they started in.
110 void insertionSort<T>(List<T> list,
111 {int compare(T a, T b), int start: 0, int end}) {
112 // If the same method could have both positional and named optional
113 // parameters, this should be (list, [start, end], {compare}).
114 compare ??= defaultCompare<T>();
115 end ??= list.length;
116
117 for (int pos = start + 1; pos < end; pos++) {
118 int min = start;
119 int max = pos;
120 var element = list[pos];
121 while (min < max) {
122 int mid = min + ((max - min) >> 1);
123 int comparison = compare(element, list[mid]);
124 if (comparison < 0) {
125 max = mid;
126 } else {
127 min = mid + 1;
128 }
129 }
130 list.setRange(min + 1, pos + 1, list, min);
131 list[min] = element;
132 }
133 }
134
135 /// Limit below which merge sort defaults to insertion sort.
136 const int _MERGE_SORT_LIMIT = 32;
137
138 /// Sorts a list between [start] (inclusive) and [end] (exclusive) using the
139 /// merge sort algorithm.
140 ///
141 /// If [compare] is omitted, this defaults to calling [Comparable.compareTo] on
142 /// the objects. If any object is not [Comparable], this throws a [CastError].
143 ///
144 /// Merge-sorting works by splitting the job into two parts, sorting each
145 /// recursively, and then merging the two sorted parts.
146 ///
147 /// This takes on the order of `n * log(n)` comparisons and moves to sort
148 /// `n` elements, but requires extra space of about the same size as the list
149 /// being sorted.
150 ///
151 /// This merge sort is stable: Equal elements end up in the same order
152 /// as they started in.
153 void mergeSort<T>(List<T> list,
154 {int start: 0, int end, int compare(T a, T b)}) {
155 end ??= list.length;
156 compare ??= defaultCompare<T>();
157
158 int length = end - start;
159 if (length < 2) return;
160 if (length < _MERGE_SORT_LIMIT) {
161 insertionSort(list, compare: compare, start: start, end: end);
162 return;
163 }
164 // Special case the first split instead of directly calling
165 // _mergeSort, because the _mergeSort requires its target to
166 // be different from its source, and it requires extra space
167 // of the same size as the list to sort.
168 // This split allows us to have only half as much extra space,
169 // and it ends up in the original place.
170 int middle = start + ((end - start) >> 1);
171 int firstLength = middle - start;
172 int secondLength = end - middle;
173 // secondLength is always the same as firstLength, or one greater.
174 var scratchSpace = new List<T>(secondLength);
175 _mergeSort(list, compare, middle, end, scratchSpace, 0);
176 int firstTarget = end - firstLength;
177 _mergeSort(list, compare, start, middle, list, firstTarget);
178 _merge(compare, list, firstTarget, end, scratchSpace, 0, secondLength, list,
179 start);
180 }
181
182 /// Performs an insertion sort into a potentially different list than the
183 /// one containing the original values.
184 ///
185 /// It will work in-place as well.
186 void _movingInsertionSort<T>(List<T> list, int compare(T a, T b), int start,
187 int end, List<T> target, int targetOffset) {
188 int length = end - start;
189 if (length == 0) return;
190 target[targetOffset] = list[start];
191 for (int i = 1; i < length; i++) {
192 var element = list[start + i];
193 int min = targetOffset;
194 int max = targetOffset + i;
195 while (min < max) {
196 int mid = min + ((max - min) >> 1);
197 if (compare(element, target[mid]) < 0) {
198 max = mid;
199 } else {
200 min = mid + 1;
201 }
202 }
203 target.setRange(min + 1, targetOffset + i + 1, target, min);
204 target[min] = element;
205 }
206 }
207
208 /// Sorts [list] from [start] to [end] into [target] at [targetOffset].
209 ///
210 /// The `target` list must be able to contain the range from `start` to `end`
211 /// after `targetOffset`.
212 ///
213 /// Allows target to be the same list as [list], as long as it's not
214 /// overlapping the `start..end` range.
215 void _mergeSort<T>(List<T> list, int compare(T a, T b), int start, int end,
216 List<T> target, int targetOffset) {
217 int length = end - start;
218 if (length < _MERGE_SORT_LIMIT) {
219 _movingInsertionSort(list, compare, start, end, target, targetOffset);
220 return;
221 }
222 int middle = start + (length >> 1);
223 int firstLength = middle - start;
224 int secondLength = end - middle;
225 // Here secondLength >= firstLength (differs by at most one).
226 int targetMiddle = targetOffset + firstLength;
227 // Sort the second half into the end of the target area.
228 _mergeSort(list, compare, middle, end, target, targetMiddle);
229 // Sort the first half into the end of the source area.
230 _mergeSort(list, compare, start, middle, list, middle);
231 // Merge the two parts into the target area.
232 _merge(compare, list, middle, middle + firstLength, target, targetMiddle,
233 targetMiddle + secondLength, target, targetOffset);
234 }
235
236 /// Merges two lists into a target list.
237 ///
238 /// One of the input lists may be positioned at the end of the target
239 /// list.
240 ///
241 /// For equal object, elements from [firstList] are always preferred.
242 /// This allows the merge to be stable if the first list contains elements
243 /// that started out earlier than the ones in [secondList]
244 void _merge<T>(
245 int compare(T a, T b),
246 List<T> firstList,
247 int firstStart,
248 int firstEnd,
249 List<T> secondList,
250 int secondStart,
251 int secondEnd,
252 List<T> target,
253 int targetOffset) {
254 // No empty lists reaches here.
255 assert(firstStart < firstEnd);
256 assert(secondStart < secondEnd);
257 int cursor1 = firstStart;
258 int cursor2 = secondStart;
259 var firstElement = firstList[cursor1++];
260 var secondElement = secondList[cursor2++];
261 while (true) {
262 if (compare(firstElement, secondElement) <= 0) {
263 target[targetOffset++] = firstElement;
264 if (cursor1 == firstEnd) break; // Flushing second list after loop.
265 firstElement = firstList[cursor1++];
266 } else {
267 target[targetOffset++] = secondElement;
268 if (cursor2 != secondEnd) {
269 secondElement = secondList[cursor2++];
270 continue;
271 }
272 // Second list empties first. Flushing first list here.
273 target[targetOffset++] = firstElement;
274 target.setRange(targetOffset, targetOffset + (firstEnd - cursor1),
275 firstList, cursor1);
276 return;
277 }
278 }
279 // First list empties first. Reached by break above.
280 target[targetOffset++] = secondElement;
281 target.setRange(
282 targetOffset, targetOffset + (secondEnd - cursor2), secondList, cursor2);
283 }
OLDNEW
« no previous file with comments | « packages/collection/lib/priority_queue.dart ('k') | packages/collection/lib/src/canonicalized_map.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698