Line data Source code
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 : import 'dart:collection';
6 :
7 : import 'utils.dart';
8 :
9 : /// A priority queue is a priority based work-list of elements.
10 : ///
11 : /// The queue allows adding elements, and removing them again in priority order.
12 : /// The same object can be added to the queue more than once.
13 : /// There is no specified ordering for objects with the same priority
14 : /// (where the `comparison` function returns zero).
15 : ///
16 : /// Operations which care about object equality, [contains] and [remove],
17 : /// use [Object.==] for testing equality.
18 : /// In most situations this will be the same as identity ([identical]),
19 : /// but there are types, like [String], where users can reasonably expect
20 : /// distinct objects to represent the same value.
21 : /// If elements override [Object.==], the `comparison` function must
22 : /// always give equal objects the same priority,
23 : /// otherwise [contains] or [remove] might not work correctly.
24 : abstract class PriorityQueue<E> {
25 : /// Creates an empty [PriorityQueue].
26 : ///
27 : /// The created [PriorityQueue] is a plain [HeapPriorityQueue].
28 : ///
29 : /// The [comparison] is a [Comparator] used to compare the priority of
30 : /// elements. An element that compares as less than another element has
31 : /// a higher priority.
32 : ///
33 : /// If [comparison] is omitted, it defaults to [Comparable.compare]. If this
34 : /// is the case, `E` must implement [Comparable], and this is checked at
35 : /// runtime for every comparison.
36 : factory PriorityQueue([int Function(E, E)? comparison]) =
37 : HeapPriorityQueue<E>;
38 :
39 : /// Number of elements in the queue.
40 : int get length;
41 :
42 : /// Whether the queue is empty.
43 : bool get isEmpty;
44 :
45 : /// Whether the queue has any elements.
46 : bool get isNotEmpty;
47 :
48 : /// Checks if [object] is in the queue.
49 : ///
50 : /// Returns true if the element is found.
51 : ///
52 : /// Uses the [Object.==] of elements in the queue to check
53 : /// for whether they are equal to [object].
54 : /// Equal objects objects must have the same priority
55 : /// according to the [comparison] function.
56 : /// That is, if `a == b` then `comparison(a, b) == 0`.
57 : /// If that is not the case, this check might fail to find
58 : /// an object.
59 : bool contains(E object);
60 :
61 : /// Provides efficient access to all the elements curently in the queue.
62 : ///
63 : /// The operation should be performed without copying or moving
64 : /// the elements, if at all possible.
65 : ///
66 : /// The elements are iterated in no particular order.
67 : /// The order is stable as long as the queue is not modified.
68 : /// The queue must not be modified during an iteration.
69 : Iterable<E> get unorderedElements;
70 :
71 : /// Adds element to the queue.
72 : ///
73 : /// The element will become the next to be removed by [removeFirst]
74 : /// when all elements with higher priority have been removed.
75 : void add(E element);
76 :
77 : /// Adds all [elements] to the queue.
78 : void addAll(Iterable<E> elements);
79 :
80 : /// Returns the next element that will be returned by [removeFirst].
81 : ///
82 : /// The element is not removed from the queue.
83 : ///
84 : /// The queue must not be empty when this method is called.
85 : E get first;
86 :
87 : /// Removes and returns the element with the highest priority.
88 : ///
89 : /// Repeatedly calling this method, without adding element in between,
90 : /// is guaranteed to return elements in non-decreasing order as, specified by
91 : /// [comparison].
92 : ///
93 : /// The queue must not be empty when this method is called.
94 : E removeFirst();
95 :
96 : /// Removes an element of the queue that compares equal to [element].
97 : ///
98 : /// Returns true if an element is found and removed,
99 : /// and false if no equal element is found.
100 : ///
101 : /// If the queue contains more than one object equal to [element],
102 : /// only one of them is removed.
103 : ///
104 : /// Uses the [Object.==] of elements in the queue to check
105 : /// for whether they are equal to [element].
106 : /// Equal objects objects must have the same priority
107 : /// according to the [comparison] function.
108 : /// That is, if `a == b` then `comparison(a, b) == 0`.
109 : /// If that is not the case, this check might fail to find
110 : /// an object.
111 : bool remove(E element);
112 :
113 : /// Removes all the elements from this queue and returns them.
114 : ///
115 : /// The returned iterable has no specified order.
116 : Iterable<E> removeAll();
117 :
118 : /// Removes all the elements from this queue.
119 : void clear();
120 :
121 : /// Returns a list of the elements of this queue in priority order.
122 : ///
123 : /// The queue is not modified.
124 : ///
125 : /// The order is the order that the elements would be in if they were
126 : /// removed from this queue using [removeFirst].
127 : List<E> toList();
128 :
129 : /// Returns a list of the elements of this queue in no specific order.
130 : ///
131 : /// The queue is not modified.
132 : ///
133 : /// The order of the elements is implementation specific.
134 : /// The order may differ between different calls on the same queue.
135 : List<E> toUnorderedList();
136 :
137 : /// Return a comparator based set using the comparator of this queue.
138 : ///
139 : /// The queue is not modified.
140 : ///
141 : /// The returned [Set] is currently a [SplayTreeSet],
142 : /// but this may change as other ordered sets are implemented.
143 : ///
144 : /// The set contains all the elements of this queue.
145 : /// If an element occurs more than once in the queue,
146 : /// the set will contain it only once.
147 : Set<E> toSet();
148 : }
149 :
150 : /// Heap based priority queue.
151 : ///
152 : /// The elements are kept in a heap structure,
153 : /// where the element with the highest priority is immediately accessible,
154 : /// and modifying a single element takes
155 : /// logarithmic time in the number of elements on average.
156 : ///
157 : /// * The [add] and [removeFirst] operations take amortized logarithmic time,
158 : /// O(log(n)), but may occasionally take linear time when growing the capacity
159 : /// of the heap.
160 : /// * The [addAll] operation works as doing repeated [add] operations.
161 : /// * The [first] getter takes constant time, O(1).
162 : /// * The [clear] and [removeAll] methods also take constant time, O(1).
163 : /// * The [contains] and [remove] operations may need to search the entire
164 : /// queue for the elements, taking O(n) time.
165 : /// * The [toList] operation effectively sorts the elements, taking O(n*log(n))
166 : /// time.
167 : /// * The [toUnorderedList] operation copies, but does not sort, the elements,
168 : /// and is linear, O(n).
169 : /// * The [toSet] operation effectively adds each element to the new set, taking
170 : /// an expected O(n*log(n)) time.
171 : class HeapPriorityQueue<E> implements PriorityQueue<E> {
172 : /// Initial capacity of a queue when created, or when added to after a
173 : /// [clear].
174 : ///
175 : /// Number can be any positive value. Picking a size that gives a whole
176 : /// number of "tree levels" in the heap is only done for aesthetic reasons.
177 : static const int _INITIAL_CAPACITY = 7;
178 :
179 : /// The comparison being used to compare the priority of elements.
180 : final Comparator<E> comparison;
181 :
182 : /// List implementation of a heap.
183 : List<E?> _queue = List<E?>.filled(_INITIAL_CAPACITY, null);
184 :
185 : /// Number of elements in queue.
186 : ///
187 : /// The heap is implemented in the first [_length] entries of [_queue].
188 : int _length = 0;
189 :
190 : /// Modification count.
191 : ///
192 : /// Used to detect concurrent modifications during iteration.
193 : int _modificationCount = 0;
194 :
195 : /// Create a new priority queue.
196 : ///
197 : /// The [comparison] is a [Comparator] used to compare the priority of
198 : /// elements. An element that compares as less than another element has
199 : /// a higher priority.
200 : ///
201 : /// If [comparison] is omitted, it defaults to [Comparable.compare]. If this
202 : /// is the case, `E` must implement [Comparable], and this is checked at
203 : /// runtime for every comparison.
204 0 : HeapPriorityQueue([int Function(E, E)? comparison])
205 : : comparison = comparison ?? defaultCompare;
206 :
207 0 : E _elementAt(int index) => _queue[index] ?? (null as E);
208 :
209 0 : @override
210 : void add(E element) {
211 0 : _modificationCount++;
212 0 : _add(element);
213 : }
214 :
215 0 : @override
216 : void addAll(Iterable<E> elements) {
217 : var modified = 0;
218 0 : for (var element in elements) {
219 : modified = 1;
220 0 : _add(element);
221 : }
222 0 : _modificationCount += modified;
223 : }
224 :
225 0 : @override
226 : void clear() {
227 0 : _modificationCount++;
228 0 : _queue = const [];
229 0 : _length = 0;
230 : }
231 :
232 0 : @override
233 0 : bool contains(E object) => _locate(object) >= 0;
234 :
235 : /// Provides efficient access to all the elements curently in the queue.
236 : ///
237 : /// The operation is performed in the order they occur
238 : /// in the underlying heap structure.
239 : ///
240 : /// The order is stable as long as the queue is not modified.
241 : /// The queue must not be modified during an iteration.
242 0 : @override
243 0 : Iterable<E> get unorderedElements => _UnorderedElementsIterable<E>(this);
244 :
245 0 : @override
246 : E get first {
247 0 : if (_length == 0) throw StateError('No element');
248 0 : return _elementAt(0);
249 : }
250 :
251 0 : @override
252 0 : bool get isEmpty => _length == 0;
253 :
254 0 : @override
255 0 : bool get isNotEmpty => _length != 0;
256 :
257 0 : @override
258 0 : int get length => _length;
259 :
260 0 : @override
261 : bool remove(E element) {
262 0 : var index = _locate(element);
263 0 : if (index < 0) return false;
264 0 : _modificationCount++;
265 0 : var last = _removeLast();
266 0 : if (index < _length) {
267 0 : var comp = comparison(last, element);
268 0 : if (comp <= 0) {
269 0 : _bubbleUp(last, index);
270 : } else {
271 0 : _bubbleDown(last, index);
272 : }
273 : }
274 : return true;
275 : }
276 :
277 : /// Removes all the elements from this queue and returns them.
278 : ///
279 : /// The returned iterable has no specified order.
280 : /// The operation does not copy the elements,
281 : /// but instead keeps them in the existing heap structure,
282 : /// and iterates over that directly.
283 0 : @override
284 : Iterable<E> removeAll() {
285 0 : _modificationCount++;
286 0 : var result = _queue;
287 0 : var length = _length;
288 0 : _queue = const [];
289 0 : _length = 0;
290 0 : return result.take(length).cast();
291 : }
292 :
293 0 : @override
294 : E removeFirst() {
295 0 : if (_length == 0) throw StateError('No element');
296 0 : _modificationCount++;
297 0 : var result = _elementAt(0);
298 0 : var last = _removeLast();
299 0 : if (_length > 0) {
300 0 : _bubbleDown(last, 0);
301 : }
302 : return result;
303 : }
304 :
305 0 : @override
306 0 : List<E> toList() => _toUnorderedList()..sort(comparison);
307 :
308 0 : @override
309 : Set<E> toSet() {
310 0 : var set = SplayTreeSet<E>(comparison);
311 0 : for (var i = 0; i < _length; i++) {
312 0 : set.add(_elementAt(i));
313 : }
314 : return set;
315 : }
316 :
317 0 : @override
318 0 : List<E> toUnorderedList() => _toUnorderedList();
319 :
320 0 : List<E> _toUnorderedList() =>
321 0 : [for (var i = 0; i < _length; i++) _elementAt(i)];
322 :
323 : /// Returns some representation of the queue.
324 : ///
325 : /// The format isn't significant, and may change in the future.
326 0 : @override
327 : String toString() {
328 0 : return _queue.take(_length).toString();
329 : }
330 :
331 : /// Add element to the queue.
332 : ///
333 : /// Grows the capacity if the backing list is full.
334 0 : void _add(E element) {
335 0 : if (_length == _queue.length) _grow();
336 0 : _bubbleUp(element, _length++);
337 : }
338 :
339 : /// Find the index of an object in the heap.
340 : ///
341 : /// Returns -1 if the object is not found.
342 : ///
343 : /// A matching object, `o`, must satisfy that
344 : /// `comparison(o, object) == 0 && o == object`.
345 0 : int _locate(E object) {
346 0 : if (_length == 0) return -1;
347 : // Count positions from one instead of zero. This gives the numbers
348 : // some nice properties. For example, all right children are odd,
349 : // their left sibling is even, and the parent is found by shifting
350 : // right by one.
351 : // Valid range for position is [1.._length], inclusive.
352 : var position = 1;
353 : // Pre-order depth first search, omit child nodes if the current
354 : // node has lower priority than [object], because all nodes lower
355 : // in the heap will also have lower priority.
356 : do {
357 0 : var index = position - 1;
358 0 : var element = _elementAt(index);
359 0 : var comp = comparison(element, object);
360 0 : if (comp <= 0) {
361 0 : if (comp == 0 && element == object) return index;
362 : // Element may be in subtree.
363 : // Continue with the left child, if it is there.
364 0 : var leftChildPosition = position * 2;
365 0 : if (leftChildPosition <= _length) {
366 : position = leftChildPosition;
367 : continue;
368 : }
369 : }
370 : // Find the next right sibling or right ancestor sibling.
371 : do {
372 0 : while (position.isOdd) {
373 : // While position is a right child, go to the parent.
374 0 : position >>= 1;
375 : }
376 : // Then go to the right sibling of the left-child.
377 0 : position += 1;
378 0 : } while (position > _length); // Happens if last element is a left child.
379 0 : } while (position != 1); // At root again. Happens for right-most element.
380 0 : return -1;
381 : }
382 :
383 0 : E _removeLast() {
384 0 : var newLength = _length - 1;
385 0 : var last = _elementAt(newLength);
386 0 : _queue[newLength] = null;
387 0 : _length = newLength;
388 : return last;
389 : }
390 :
391 : /// Place [element] in heap at [index] or above.
392 : ///
393 : /// Put element into the empty cell at `index`.
394 : /// While the `element` has higher priority than the
395 : /// parent, swap it with the parent.
396 0 : void _bubbleUp(E element, int index) {
397 0 : while (index > 0) {
398 0 : var parentIndex = (index - 1) ~/ 2;
399 0 : var parent = _elementAt(parentIndex);
400 0 : if (comparison(element, parent) > 0) break;
401 0 : _queue[index] = parent;
402 : index = parentIndex;
403 : }
404 0 : _queue[index] = element;
405 : }
406 :
407 : /// Place [element] in heap at [index] or above.
408 : ///
409 : /// Put element into the empty cell at `index`.
410 : /// While the `element` has lower priority than either child,
411 : /// swap it with the highest priority child.
412 0 : void _bubbleDown(E element, int index) {
413 0 : var rightChildIndex = index * 2 + 2;
414 0 : while (rightChildIndex < _length) {
415 0 : var leftChildIndex = rightChildIndex - 1;
416 0 : var leftChild = _elementAt(leftChildIndex);
417 0 : var rightChild = _elementAt(rightChildIndex);
418 0 : var comp = comparison(leftChild, rightChild);
419 : int minChildIndex;
420 : E minChild;
421 0 : if (comp < 0) {
422 : minChild = leftChild;
423 : minChildIndex = leftChildIndex;
424 : } else {
425 : minChild = rightChild;
426 : minChildIndex = rightChildIndex;
427 : }
428 0 : comp = comparison(element, minChild);
429 0 : if (comp <= 0) {
430 0 : _queue[index] = element;
431 : return;
432 : }
433 0 : _queue[index] = minChild;
434 : index = minChildIndex;
435 0 : rightChildIndex = index * 2 + 2;
436 : }
437 0 : var leftChildIndex = rightChildIndex - 1;
438 0 : if (leftChildIndex < _length) {
439 0 : var child = _elementAt(leftChildIndex);
440 0 : var comp = comparison(element, child);
441 0 : if (comp > 0) {
442 0 : _queue[index] = child;
443 : index = leftChildIndex;
444 : }
445 : }
446 0 : _queue[index] = element;
447 : }
448 :
449 : /// Grows the capacity of the list holding the heap.
450 : ///
451 : /// Called when the list is full.
452 0 : void _grow() {
453 0 : var newCapacity = _queue.length * 2 + 1;
454 0 : if (newCapacity < _INITIAL_CAPACITY) newCapacity = _INITIAL_CAPACITY;
455 0 : var newQueue = List<E?>.filled(newCapacity, null);
456 0 : newQueue.setRange(0, _length, _queue);
457 0 : _queue = newQueue;
458 : }
459 : }
460 :
461 : /// Implementation of [HeapPriorityQueue.unorderedElements].
462 : class _UnorderedElementsIterable<E> extends Iterable<E> {
463 : final HeapPriorityQueue<E> _queue;
464 0 : _UnorderedElementsIterable(this._queue);
465 0 : @override
466 0 : Iterator<E> get iterator => _UnorderedElementsIterator<E>(_queue);
467 : }
468 :
469 : class _UnorderedElementsIterator<E> implements Iterator<E> {
470 : final HeapPriorityQueue<E> _queue;
471 : final int _initialModificationCount;
472 : E? _current;
473 : int _index = -1;
474 :
475 0 : _UnorderedElementsIterator(this._queue)
476 0 : : _initialModificationCount = _queue._modificationCount;
477 :
478 0 : @override
479 : bool moveNext() {
480 0 : if (_initialModificationCount != _queue._modificationCount) {
481 0 : throw ConcurrentModificationError(_queue);
482 : }
483 0 : var nextIndex = _index + 1;
484 0 : if (0 <= nextIndex && nextIndex < _queue.length) {
485 0 : _current = _queue._queue[nextIndex];
486 0 : _index = nextIndex;
487 : return true;
488 : }
489 0 : _current = null;
490 0 : _index = -2;
491 : return false;
492 : }
493 :
494 0 : @override
495 : E get current =>
496 0 : _index < 0 ? throw StateError('No element') : (_current ?? null as E);
497 : }
|