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

Side by Side Diff: pkg/collection/lib/priority_queue.dart

Issue 110483006: Add priority queue to package:collection. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Improve test layout/comments. Created 6 years, 11 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 | Annotate | Revision Log
« no previous file with comments | « pkg/collection/lib/collection.dart ('k') | pkg/collection/pubspec.yaml » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2014, 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 library dart.pkg.collection.priority_queue;
6
7 import "dart:collection" show SplayTreeSet;
8
9 /**
10 * A priority queue is a priority based work-list of elements.
11 *
12 * The queue allows adding elements, and removing them again in priority order.
13 */
14 abstract class PriorityQueue<E> {
15 /**
16 * Number of elements in the queue.
17 */
18 int get length;
19
20 /**
21 * Whether the queue is empty.
22 */
23 bool get isEmpty;
24
25 /**
26 * Whether the queue has any elements.
27 */
28 bool get isNotEmpty;
29
30 /**
31 * Checks if [object] is in the queue.
32 *
33 * Returns true if the element is found.
34 */
35 bool contains(E object);
36
37 /**
38 * Returns the next element that will be returned by [removeFirst].
39 *
40 * The element is not removed from the queue.
41 *
42 * The queue must not be empty when this method is called.
43 */
44 E get first;
45
46 /**
47 * Removes and returns the element with the highest priority.
48 *
49 * Repeatedly calling this method, without adding element in between,
50 * is guaranteed to return elements in non-decreasing order as, specified by
51 * [comparison].
52 *
53 * The queue must not be empty when this method is called.
54 */
55 E removeFirst();
56
57 /**
58 * Removes an element that compares equal to [element] in the queue.
59 *
60 * Returns true if an element is found and removed,
61 * and false if not equal element is found.
62 */
63 bool remove(E element);
64
65 /**
66 * Removes all the elements from this queue and returns them.
67 *
68 * The returned iterable has no specified order.
69 */
70 Iterable<E> removeAll();
71
72 /**
73 * Removes all the elements from this queue.
74 */
75 void clear();
76
77 /**
78 * Returns a list of the elements of this queue in priority order.
79 *
80 * The queue is not modified.
81 *
82 * The order is the order that the elements would be in if they were
83 * removed from this queue using [removeFirst].
84 */
85 List<E> toList();
86
87 /**
88 * Return a comparator based set using the comparator of this queue.
89 *
90 * The queue is not modified.
91 *
92 * The returned [Set] is currently a [SplayTreeSet],
93 * but this may change as other ordered sets are implemented.
94 *
95 * The set contains all the elements of this queue.
96 * If an element occurs more than once in the queue,
97 * the set will contain it only once.
98 */
99 Set<E> toSet();
100 }
101
102 /**
103 * Heap based priority queue.
104 *
105 * The elements are kept in a heap structure,
106 * where the element with the highest priority is immediately accessible,
107 * and modifying a single element takes
108 * logarithmic time in the number of elements on average.
109 *
110 * * The [add] and [removeFirst] operations take amortized logarithmic time,
111 * O(log(n)), but may occasionally take linear time when growing the capacity
112 * of the heap.
113 * * The [addAll] operation works as doing repeated [add] operations.
114 * * The [first] getter takes constant time, O(1).
115 * * The [clear] and [removeAll] methods also take constant time, O(1).
116 * * The [contains] and [remove] operations may need to search the entire
117 * queue for the elements, taking O(n) time.
118 * * The [toList] operation effectively sorts the elements, taking O(n*log(n))
119 * time.
120 * * The [toSet] operation effectively adds each element to the new set, taking
121 * an expected O(n*log(n)) time.
122 */
123 class HeapPriorityQueue<E> implements PriorityQueue<E> {
124 /**
125 * Initial capacity of a queue when created, or when added to after a [clear].
126 *
127 * Number can be any positive value. Picking a size that gives a whole
128 * number of "tree levels" in the heap is only done for aesthetic reasons.
129 */
130 static const int _INITIAL_CAPACITY = 7;
131
132 /**
133 * The comparison being used to compare the priority of elements.
134 */
135 final Comparator comparison;
136
137 /**
138 * List implementation of a heap.
139 */
140 List<E> _queue = new List<E>(_INITIAL_CAPACITY);
141
142 /**
143 * Number of elements in queue.
144 *
145 * The heap is implemented in the first [_length] entries of [_queue].
146 */
147 int _length = 0;
148
149 /**
150 * Create a new priority queue.
151 *
152 * The [comparison] is a [Comparator] used to compare the priority of
153 * elements. An element that compares as less than another element has
154 * a higher priority.
155 *
156 * If [comparison] is omitted, it defaults to [Comparable.compare].
157 */
158 HeapPriorityQueue([int comparison(E e1, E e2)])
159 : comparison = (comparison != null) ? comparison : Comparable.compare;
160
161 void add(E element) {
162 _add(element);
163 }
164
165 void addAll(Iterable<E> elements) {
166 for (E element in elements) {
167 _add(element);
168 }
169 }
170
171 void clear() {
172 _queue = const [];
173 _length = 0;
174 }
175
176 bool contains(E object) {
177 return _locate(object) >= 0;
178 }
179
180 E get first {
181 if (_length == 0) throw new StateError("No such element");
182 return _queue[0];
183 }
184
185 bool get isEmpty => _length == 0;
186
187 bool get isNotEmpty => _length != 0;
188
189 int get length => _length;
190
191 bool remove(E element) {
192 int index = _locate(element);
193 if (index < 0) return false;
194 E last = _removeLast();
195 if (index < _length) {
196 int comp = comparison(last, element);
197 if (comp <= 0) {
198 _bubbleUp(last, index);
199 } else {
200 _bubbleDown(last, index);
201 }
202 }
203 return true;
204 }
205
206 Iterable<E> removeAll() {
207 List<E> result = _queue;
208 int length = _length;
209 _queue = const [];
210 _length = 0;
211 return result.take(length);
212 }
213
214 E removeFirst() {
215 if (_length == 0) throw new StateError("No such element");
216 E result = _queue[0];
217 E last = _removeLast();
218 if (_length > 0) {
219 _bubbleDown(last, 0);
220 }
221 return result;
222 }
223
224 List<E> toList() {
225 List<E> list = new List<E>()..length = _length;
226 list.setRange(0, _length, _queue);
227 list.sort(comparison);
228 return list;
229 }
230
231 Set<E> toSet() {
232 Set<E> set = new SplayTreeSet<E>(comparison);
233 for (int i = 0; i < _length; i++) {
234 set.add(_queue[i]);
235 }
236 return set;
237 }
238
239 /**
240 * Returns some representation of the queue.
241 *
242 * The format isn't significant, and may change in the future.
243 */
244 String toString() {
245 return _queue.take(_length).toString();
246 }
247
248 /**
249 * Add element to the queue.
250 *
251 * Grows the capacity if the backing list is full.
252 */
253 void _add(E element) {
254 if (_length == _queue.length) _grow();
255 _bubbleUp(element, _length++);
256 }
257
258 /**
259 * Find the index of an object in the heap.
260 *
261 * Returns -1 if the object is not found.
262 */
263 int _locate(E object) {
264 if (_length == 0) return -1;
265 // Count positions from one instad of zero. This gives the numbers
266 // some nice properties. For example, all right children are odd,
267 // their left sibling is even, and the parent is found by shifting
268 // right by one.
269 // Valid range for position is [1.._length], inclusive.
270 int position = 1;
271 // Pre-order depth first search, omit child nodes if the current
272 // node has lower priority than [object], because all nodes lower
273 // in the heap will also have lower priority.
274 do {
275 int index = position - 1;
276 E element = _queue[index];
277 int comp = comparison(element, object);
278 if (comp == 0) return index;
279 if (comp < 0) {
280 // Element may be in subtree.
281 // Continue with the left child, if it is there.
282 int leftChildPosition = position * 2;
283 if (leftChildPosition <= _length) {
284 position = leftChildPosition;
285 continue;
286 }
287 }
288 // Find the next right sibling or right ancestor sibling.
289 do {
290 while (position.isOdd) {
291 // While position is a right child, go to the parent.
292 position >>= 1;
293 }
294 // Then go to the right sibling of the left-child.
295 position += 1;
296 } while (position > _length); // Happens if last element is a left child.
297 } while (position != 1); // At root again. Happens for right-most element.
298 return -1;
299 }
300
301 E _removeLast() {
302 int newLength = _length - 1;
303 E last = _queue[newLength];
304 _queue[newLength] = null;
305 _length = newLength;
306 return last;
307 }
308
309 /**
310 * Place [element] in heap at [index] or above.
311 *
312 * Put element into the empty cell at `index`.
313 * While the `element` has higher priority than the
314 * parent, swap it with the parent.
315 */
316 void _bubbleUp(E element, int index) {
317 while (index > 0) {
318 int parentIndex = (index - 1) ~/ 2;
319 E parent = _queue[parentIndex];
320 if (comparison(element, parent) > 0) break;
321 _queue[index] = parent;
322 index = parentIndex;
323 }
324 _queue[index] = element;
325 }
326
327 /**
328 * Place [element] in heap at [index] or above.
329 *
330 * Put element into the empty cell at `index`.
331 * While the `element` has lower priority than either child,
332 * swap it with the highest priority child.
333 */
334 void _bubbleDown(E element, int index) {
335 int rightChildIndex = index * 2 + 2;
336 while (rightChildIndex < _length) {
337 int leftChildIndex = rightChildIndex - 1;
338 E leftChild = _queue[leftChildIndex];
339 E rightChild = _queue[rightChildIndex];
340 int comp = comparison(leftChild, rightChild);
341 int minChildIndex;
342 E minChild;
343 if (comp < 0) {
344 minChild = leftChild;
345 minChildIndex = leftChildIndex;
346 } else {
347 minChild = rightChild;
348 minChildIndex = rightChildIndex;
349 }
350 comp = comparison(element, minChild);
351 if (comp <= 0) {
352 _queue[index] = element;
353 return;
354 }
355 _queue[index] = minChild;
356 index = minChildIndex;
357 rightChildIndex = index * 2 + 2;
358 }
359 int leftChildIndex = rightChildIndex - 1;
360 if (leftChildIndex < _length) {
361 E child = _queue[leftChildIndex];
362 int comp = comparison(element, child);
363 if (comp > 0) {
364 _queue[index] = child;
365 index = leftChildIndex;
366 }
367 }
368 _queue[index] = element;
369 }
370
371 /**
372 * Grows the capacity of the list holding the heap.
373 *
374 * Called when the list is full.
375 */
376 void _grow() {
377 int newCapacity = _queue.length * 2 + 1;
378 if (newCapacity < _INITIAL_CAPACITY) newCapacity = _INITIAL_CAPACITY;
379 List<E> newQueue = new List<E>(newCapacity);
380 newQueue.setRange(0, _length, _queue);
381 _queue = newQueue;
382 }
383 }
OLDNEW
« no previous file with comments | « pkg/collection/lib/collection.dart ('k') | pkg/collection/pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698