Ejemplo n.º 1
0
 /// <summary>
 ///     A helper function to add a node to the right of this one in the current
 ///     circularly doubly linked list.
 /// </summary>
 /// <param name="node">A node to go in the linked list.</param>
 public void AddRight(FHeapNode <T> node)
 {
     Right.Left = node;
     node.Right = Right;
     node.Left  = this;
     Right      = node;
 }
Ejemplo n.º 2
0
        /// <summary>
        ///     Remove x from the child list of y.
        /// </summary>
        /// <param name="x">A child of y we just decreased the value of.</param>
        /// <param name="y">The now former parent of x.</param>
        protected void Cut(FHeapNode <T> x, FHeapNode <T> y)
        {
            if (MinItem == null)
            {
                throw new InvalidOperationException("Heap malformed");
            }

            if (y.Degree == 1)
            {
                y.Child = null;
                MinItem.AddRight(x);
            }
            else if (y.Degree > 1)
            {
                x.Remove();
            }
            else
            {
                throw new InvalidOperationException("Heap malformed");
            }

            y.Degree--;
            x.Mark   = false;
            x.Parent = null;
        }
Ejemplo n.º 3
0
        /// <summary>
        ///     Reduce the key of x to be k.
        /// </summary>
        /// <remarks>
        ///     k must be less than x.Key, increasing the key of an item is not supported.
        /// </remarks>
        /// <param name="x">The item you want to reduce in value.</param>
        /// <param name="k">The new value for the item.</param>
        public void DecreaseKey(FHeapNode <T> x, T k)
        {
            if (MinItem == null)
            {
                throw new ArgumentException($"{nameof(x)} is not from the heap");
            }

            if (x.Key == null)
            {
                throw new ArgumentException("x has no value");
            }

            if (k.CompareTo(x.Key) > 0)
            {
                throw new InvalidOperationException("Value cannot be increased");
            }

            x.Key = k;
            var y = x.Parent;

            if (y != null && x.Key.CompareTo(y.Key) < 0)
            {
                Cut(x, y);
                CascadingCut(y);
            }

            if (x.Key.CompareTo(MinItem.Key) < 0)
            {
                MinItem = x;
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        ///     Combine the linked list that <c>otherList</c> sits inside, with the
        ///     linked list this is in. Do this by cutting the link between this node,
        ///     and the node to the right of this, and inserting the contents of the
        ///     otherList in between.
        /// </summary>
        /// <param name="otherList">
        ///     A node from another list whose elements we want
        ///     to concatenate to this list.
        /// </param>
        public void ConcatenateRight(FHeapNode <T> otherList)
        {
            Right.Left           = otherList.Left;
            otherList.Left.Right = Right;

            Right          = otherList;
            otherList.Left = this;
        }
Ejemplo n.º 5
0
        /// <summary>
        ///     <para>
        ///         Consolidate is analogous to Heapify in <see cref="DataStructures.Heap.BinaryHeap{T}" />.
        ///     </para>
        ///     <para>
        ///         First, an array <c>A</c> [0...D(H.n)] is created where H.n is the number
        ///         of items in this heap, and D(x) is the max degree any node can have in a
        ///         Fibonacci heap with x nodes.
        ///     </para>
        ///     <para>
        ///         For each node <c>x</c> in the root list, try to add it to <c>A[d]</c> where
        ///         d is the degree of <c>x</c>.
        ///         If there is already a node in <c>A[d]</c>, call it <c>y</c>, and make
        ///         <c>y</c> a child of <c>x</c>. (Swap <c>x</c> and <c>y</c> beforehand if
        ///         <c>x</c> is greater than <c>y</c>). Now that <c>x</c> has one more child,
        ///         remove if from <c>A[d]</c> and add it to <c>A[d+1]</c> to reflect that its
        ///         degree is one more. Loop this behavior until we find an empty spot to put
        ///         <c>x</c>.
        ///     </para>
        ///     <para>
        ///         With <c>A</c> all filled, empty the root list of the heap. And add each item
        ///         from <c>A</c> into the root list, one by one, making sure to keep track of
        ///         which is smallest.
        ///     </para>
        /// </summary>
        protected void Consolidate()
        {
            if (MinItem == null)
            {
                return;
            }

            // There's a fact in Intro to Algorithms:
            // "the max degree of any node in an n-node fibonacci heap is O(lg(n)).
            // In particular, we shall show that D(n) <= floor(log_phi(n)) where phi is
            // the golden ratio, defined in equation 3.24 as phi = (1 + sqrt(5))/2"
            //
            // For a proof, see [1]
            var maxDegree = 1 + (int)Math.Log(Count, (1 + Math.Sqrt(5)) / 2);

            // Create slots for every possible node degree of x
            var a        = new FHeapNode <T>?[maxDegree];
            var siblings = SiblingIterator(MinItem).ToList();

            foreach (var w in siblings)
            {
                var x = w;
                var d = x.Degree;

                var y = a[d];

                // While A[d] is not empty, we can't blindly put x here
                while (y != null)
                {
                    if (x.Key.CompareTo(y.Key) > 0)
                    {
                        // Exchange x and y
                        var temp = x;
                        x = y;
                        y = temp;
                    }

                    // Make y a child of x
                    FibHeapLink(y, x);

                    // Empty out this spot since x now has a higher degree
                    a[d] = null;

                    // Add 1 to x's degree before going back into the loop
                    d++;

                    y = a[d];
                }

                // Now that there's an empty spot for x, place it there
                a[d] = x;
            }

            ReconstructHeap(a);
        }
Ejemplo n.º 6
0
        /// <summary>
        ///     A helper function to iterate through all the siblings of this node in the
        ///     circularly doubly linked list.
        /// </summary>
        /// <param name="node">A node we want the siblings of.</param>
        /// <returns>An iterator over all of the siblings.</returns>
        private IEnumerable <FHeapNode <T> > SiblingIterator(FHeapNode <T> node)
        {
            var currentNode = node;

            yield return(currentNode);

            currentNode = node.Right;
            while (currentNode != node)
            {
                yield return(currentNode);

                currentNode = currentNode.Right;
            }
        }
Ejemplo n.º 7
0
        /// <summary>
        ///     Similar to AddRight, but adds the node as a sibling to the child node.
        /// </summary>
        /// <param name="node">A node to add to the child list of this node.</param>
        public void AddChild(FHeapNode <T> node)
        {
            Degree++;

            if (Child == null)
            {
                Child        = node;
                Child.Parent = this;
                Child.Left   = Child.Right = Child;

                return;
            }

            Child.AddRight(node);
        }
Ejemplo n.º 8
0
        /// <summary>
        ///     Rebalances the heap after the decrease operation takes place.
        /// </summary>
        /// <param name="y">An item that may no longer obey the heap property.</param>
        protected void CascadingCut(FHeapNode <T> y)
        {
            var z = y.Parent;

            if (z != null)
            {
                if (!y.Mark)
                {
                    y.Mark = true;
                }
                else
                {
                    Cut(y, z);
                    CascadingCut(z);
                }
            }
        }
Ejemplo n.º 9
0
        /// <summary>
        ///     Return the MinItem and remove it from the heap.
        /// </summary>
        /// <remarks>
        ///     This function (with all of its helper functions) is the most complicated
        ///     part of the Fibonacci Heap. However, it can be broken down into a few steps.
        ///     <list type="number">
        ///         <item>
        ///             Add the children of MinItem to the root list. Either one of these children,
        ///             or another of the items in the root list is a candidate to become the new
        ///             MinItem.
        ///         </item>
        ///         <item>
        ///             Remove the MinItem from the root list and appoint a new MinItem temporarily.
        ///         </item>
        ///         <item>
        ///             <see cref="Consolidate" /> what's left
        ///             of the heap.
        ///         </item>
        ///     </list>
        /// </remarks>
        /// <returns>The minimum item from the heap.</returns>
        public T Pop()
        {
            FHeapNode <T>?z = null;

            if (MinItem == null)
            {
                throw new InvalidOperationException("Heap is empty!");
            }

            z = MinItem;

            // Since z is leaving the heap, add its children to the root list
            if (z.Child != null)
            {
                foreach (var x in SiblingIterator(z.Child))
                {
                    x.Parent = null;
                }

                // This effectively adds each child x to the root list
                z.ConcatenateRight(z.Child);
            }

            if (Count == 1)
            {
                MinItem = null;
                Count   = 0;
                return(z.Key);
            }

            // Temporarily reassign MinItem to an arbitrary item in the root
            // list
            MinItem = MinItem.Right;

            // Remove the old MinItem from the root list altogether
            z.Remove();

            // Consolidate the heap
            Consolidate();

            Count -= 1;

            return(z.Key);
        }
Ejemplo n.º 10
0
        /// <summary>
        ///     Add item <c>x</c> to this Fibonacci heap.
        /// </summary>
        /// <remarks>
        ///     To add an item to a Fibonacci heap, we simply add it to the "root list",
        ///     a circularly doubly linked list where our minimum item sits. Since adding
        ///     items to a linked list takes O(1) time, the overall time to perform this
        ///     operation is O(1).
        /// </remarks>
        /// <param name="x">An item to push onto the heap.</param>
        /// <returns>
        ///     A reference to the item as it is in the heap. This is used for
        ///     operations like decresing key.
        /// </returns>
        public FHeapNode <T> Push(T x)
        {
            Count++;

            var newItem = new FHeapNode <T>(x);

            if (MinItem == null)
            {
                MinItem = newItem;
            }
            else
            {
                MinItem.AddRight(newItem);

                if (newItem.Key.CompareTo(MinItem.Key) < 0)
                {
                    MinItem = newItem;
                }
            }

            return(newItem);
        }
Ejemplo n.º 11
0
        /// <summary>
        ///     Reconstructs the heap based on the array of node degrees created by the consolidate step.
        /// </summary>
        /// <param name="a">An array of FHeapNodes where a[i] represents a node of degree i.</param>
        private void ReconstructHeap(FHeapNode <T>?[] a)
        {
            // Once all items are in A, empty out the root list
            MinItem = null;

            for (var i = 0; i < a.Length; i++)
            {
                var r = a[i];
                if (r == null)
                {
                    continue;
                }

                if (MinItem == null)
                {
                    // If the root list is completely empty, make this the new
                    // MinItem
                    MinItem = r;

                    // Make a new root list with just this item. Make sure to make
                    // it its own list.
                    MinItem.SetSiblings(MinItem, MinItem);
                    MinItem.Parent = null;
                }
                else
                {
                    // Add A[i] to the root list
                    MinItem.AddRight(r);

                    // If this item is smaller, make it the new min item
                    if (MinItem.Key.CompareTo(r.Key) > 0)
                    {
                        MinItem = a[i];
                    }
                }
            }
        }
Ejemplo n.º 12
0
        /// <summary>
        ///     Combines all the elements of two fibonacci heaps.
        /// </summary>
        /// <remarks>
        ///     To union two Fibonacci heaps is a single fibonacci heap is a single heap
        ///     that contains all the elements of both heaps. This can be done in O(1) time
        ///     by concatenating the root lists together.
        ///     For more details on how two circularly linked lists are concatenated, see
        ///     <see cref="FHeapNode{T}.ConcatenateRight" />
        ///     Finally, check to see which of <c>this.MinItem</c> and <c>other.MinItem</c>
        ///     is smaller, and set <c>this.MinItem</c> accordingly
        ///     This operation destroys <c>other</c>.
        /// </remarks>
        /// <param name="other">
        ///     Another heap whose elements we wish to add to this heap.
        ///     The other heap will be destroyed as a result.
        /// </param>
        public void Union(FibonacciHeap <T> other)
        {
            // If there are no items in the other heap, then there is nothing to do.
            if (other.MinItem == null)
            {
                return;
            }

            // If this heap is empty, simply set it equal to the other heap
            if (MinItem == null)
            {
                // Set this heap to the other one
                MinItem = other.MinItem;
                Count   = other.Count;

                // Destroy the other heap
                other.MinItem = null;
                other.Count   = 0;

                return;
            }

            Count += other.Count;

            // <see cref="DataStructures.FibonacciHeap{T}.FHeapNode.ConcatenateRight(DataStructures.FibonacciHeap{T}.FHeapNode)"/>
            MinItem.ConcatenateRight(other.MinItem);

            // Set the MinItem to the smaller of the two MinItems
            if (other.MinItem.Key.CompareTo(MinItem.Key) < 0)
            {
                MinItem = other.MinItem;
            }

            other.MinItem = null;
            other.Count   = 0;
        }
Ejemplo n.º 13
0
 public void SetSiblings(FHeapNode <T> left, FHeapNode <T> right)
 {
     Left  = left;
     Right = right;
 }
Ejemplo n.º 14
0
 /// <summary>
 ///     Make y a child of x.
 /// </summary>
 /// <param name="y">A node to become the child of x.</param>
 /// <param name="x">A node to become the parent of y.</param>
 private void FibHeapLink(FHeapNode <T> y, FHeapNode <T> x)
 {
     y.Remove();
     x.AddChild(y);
     y.Mark = false;
 }