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