LCOV - code coverage report
Current view: top level - collection-1.15.0/lib/src - priority_queue.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 134 0.0 %
Date: 2021-11-28 14:37:50 Functions: 0 0 -

          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             : }

Generated by: LCOV version 1.14