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