Beispiel #1
0
        /// <summary>
        /// Adds an object to the priority queue.
        /// </summary>
        internal void Push(T value, double priority)
        {
            // Increase the size of the array if necessary.
            if (_count == _heap.Length)
            {
                Array.Resize <PriorityQueueItem <T> >(ref _heap, _count * 2);
            }

            PriorityQueueItem <T> queueItem = new PriorityQueueItem <T>(value, priority);

            // A common usage is to Push N items, then Pop them.  Optimize for that
            // case by treating Push as a simple append until the first Top or Pop,
            // which establishes the heap property.  After that, Push needs
            // to maintain the heap property.
            if (_isHeap)
            {
                SiftUp(_count, ref queueItem, 0);
            }
            else
            {
                _heap[_count] = queueItem;
            }

            _count++;
        }
Beispiel #2
0
        /// <summary>
        /// Removes the first node (i.e., the logical root) from the heap.
        /// </summary>
        internal void Pop()
        {
            Debug.Assert(_count != 0);
            if (!_isHeap)
            {
                Heapify();
            }

            if (_count > 0)
            {
                --_count;

                // discarding the root creates a gap at position 0.  We fill the
                // gap with the item x from the last position, after first sifting
                // the gap to a position where inserting x will maintain the
                // heap property.  This is done in two phases - SiftDown and SiftUp.
                //
                // The one-phase method found in many textbooks does 2 comparisons
                // per level, while this method does only 1.  The one-phase method
                // examines fewer levels than the two-phase method, but it does
                // more comparisons unless x ends up in the top 2/3 of the tree.
                // That accounts for only n^(2/3) items, and x is even more likely
                // to end up near the bottom since it came from the bottom in the
                // first place.  Overall, the two-phase method is noticeably better.

                PriorityQueueItem <T> x = _heap[_count];        // lift item x out from the last position
                int index = SiftDown(0);                        // sift the gap at the root down to the bottom
                SiftUp(index, ref x, 0);                        // sift the gap up, and insert x in its rightful position
                _heap[_count] = default(PriorityQueueItem <T>); // don't leak x
            }
        }
Beispiel #3
0
 // Establish the heap property:  _heap[k] >= _heap[HeapParent(k)], for 0<k<_count
 // Do this "bottom up", by iterating backwards.  At each iteration, the
 // property inductively holds for k >= HeapLeftChild(i)+2;  the body of
 // the loop extends the property to the children of position i (namely
 // k=HLC(i) and k=HLC(i)+1) by lifting item x out from position i, sifting
 // the resulting gap down to the bottom, then sifting it back up (within
 // the subtree under i) until finding x's rightful position.
 //
 // Iteration i does work proportional to the height (distance to leaf)
 // of the node at position i.  Half the nodes are leaves with height 0;
 // there's nothing to do for these nodes, so we skip them by initializing
 // i to the last non-leaf position.  A quarter of the nodes have height 1,
 // an eigth have height 2, etc. so the total work is ~ 1*n/4 + 2*n/8 +
 // 3*n/16 + ... = O(n).  This is much cheaper than maintaining the
 // heap incrementally during the "Push" phase, which would cost O(n*log n).
 private void Heapify()
 {
     if (!_isHeap)
     {
         for (int i = _count / 2 - 1; i >= 0; --i)
         {
             // we use a two-phase method for the same reason Pop does
             PriorityQueueItem <T> x = _heap[i];
             int index = SiftDown(i);
             SiftUp(index, ref x, i);
         }
         _isHeap = true;
     }
 }
Beispiel #4
0
 // sift a gap at index up until it reaches the correct position for x,
 // or reaches the given boundary.  Place x in the resulting position.
 private void SiftUp(int index, ref PriorityQueueItem <T> x, int boundary)
 {
     while (index > boundary)
     {
         int parent = HeapParent(index);
         if (_comparer.Compare(_heap[parent], x) > 0)
         {
             _heap[index] = _heap[parent];
             index        = parent;
         }
         else
         {
             break;
         }
     }
     _heap[index] = x;
 }
Beispiel #5
0
        //
        // The _heap array represents a binary tree with the "shape" property.
        // If we number the nodes of a binary tree from left-to-right and top-
        // to-bottom as shown,
        //
        //             0
        //           /   \
        //          /     \
        //         1       2
        //       /  \     / \
        //      3    4   5   6
        //     /\    /
        //    7  8  9
        //
        // The shape property means that there are no gaps in the sequence of
        // numbered nodes, i.e., for all N > 0, if node N exists then node N-1
        // also exists. For example, the next node added to the above tree would
        // be node 10, the right child of node 4.
        //
        // Because of this constraint, we can easily represent the "tree" as an
        // array, where node number == array index, and parent/child relationships
        // can be calculated instead of maintained explicitly. For example, for
        // any node N > 0, the parent of N is at array index (N - 1) / 2.
        //
        // In addition to the above, the first _count members of the _heap array
        // compose a "heap", meaning each child node is greater than or equal to
        // its parent node; thus, the root node is always the minimum (i.e., the
        // best match for the specified style, weight, and stretch) of the nodes
        // in the heap.
        //
        // Initially _count < 0, which means we have not yet constructed the heap.
        // On the first call to MoveNext, we construct the heap by "pushing" all
        // the nodes into it. Each successive call "pops" a node off the heap
        // until the heap is empty (_count == 0), at which time we've reached the
        // end of the sequence.
        //

        #region constructors

        internal PriorityQueue(int capacity = 0)
        {
            _heap     = new PriorityQueueItem <T> [capacity > 0 ? capacity: DefaultCapacity];
            _count    = 0;
            _comparer = new PriorityQueueComparer <T>();
        }
Beispiel #6
0
 public int Compare(PriorityQueueItem <T> x, PriorityQueueItem <T> y)
 {
     return(x.Priority.CompareTo(y.Priority));
 }