Esempio n. 1
0
        public FibNode <T> Delete()
        {
            Debug.Assert(root.CheckChildren());
            logger.AddNumberOfOperations();

            Debug.Assert(currMinimum != null || numberOfElements == 0);
            if (numberOfElements == 0)
            {
                return(null);
            }

            var minimum = currMinimum;

            currMinimum = null;

            // Remove minimum from the current heap forrest.
            root.RemoveChild(minimum);
            numberOfElements--;

            Debug.Assert(numberOfElements >= 0);
            Debug.Assert(numberOfElements > 1 || root.IsEmpty);

            logger.AddValue(minimum.Children.Rank);

            // Add minimum's children to the current heap forrest.
            root.AddChildren(minimum.Children);
            Consolidate();

            Debug.Assert(root.CheckChildren());
            return(minimum);
        }
Esempio n. 2
0
        void ConnectToCurrentCyclicList(uint numberOfNewChildren, FibNode <T> newChild)
        {
            // If there's nothing new to connect, return.
            if (newChild == null)
            {
                return;
            }

            Rank += numberOfNewChildren;

            // Current CyclicForrest is empty, set the new one as current FirstChild ref.
            if (FirstChild == null)
            {
                Debug.Assert(Rank == numberOfNewChildren);
                FirstChild = newChild;
                return;
            }

            var current    = FirstChild;
            var preCurrent = current.PreviousSibling;

            var preNewChild = newChild.PreviousSibling;

            // Merge the two cyclic double linked lists.
            preCurrent.NextSibling   = newChild;
            newChild.PreviousSibling = preCurrent;

            preNewChild.NextSibling = current;
            current.PreviousSibling = preNewChild;

            Debug.Assert(CheckChildren());
        }
Esempio n. 3
0
        /// <summary>
        /// Resets node's references to a standalone tree state.
        /// </summary>
        internal void ResetSiblingsAndParentToATreeState()
        {
            Parent = null;

            NextSibling     = this;
            PreviousSibling = this;
        }
Esempio n. 4
0
        internal void RemoveChild(FibNode <T> nodeBeingRemoved)
        {
            Debug.Assert(Rank >= 1);
            Rank -= 1;

            var preNode = nodeBeingRemoved.PreviousSibling;
            var posNode = nodeBeingRemoved.NextSibling;

            if (Rank == 0)
            {
                // There's only one node, set the FirstChild ref to null.
                Debug.Assert(posNode == nodeBeingRemoved && preNode == nodeBeingRemoved);
                FirstChild = null;
            }
            else
            {
                // Connect the node before and after the one being removed, bypassing the one that is being removed.
                preNode.NextSibling     = posNode;
                posNode.PreviousSibling = preNode;

                // Update FirstChild pointer in case the item being removed is it. There is definitely another node (see if above) available.
                if (FirstChild == nodeBeingRemoved)
                {
                    FirstChild = posNode;
                }
            }

            // Fix the removed node's pointers to siblings and to parent.
            nodeBeingRemoved.ResetSiblingsAndParentToATreeState();

            Debug.Assert(CheckChildren());
        }
Esempio n. 5
0
 void UpdateMinimum(FibNode <T> node)
 {
     if (currMinimum == null)
     {
         currMinimum = node;
     }
     if (currMinimum.Weight >= node.Weight)
     {
         currMinimum = node;
     }
 }
Esempio n. 6
0
        public FibNode <T> Insert(T payload, int weight)
        {
            Debug.Assert(root.CheckChildren());
            var newNode = new FibNode <T>(payload, weight);

            UpdateMinimum(newNode);
            numberOfElements++;

            // Add the new node as a stanadone tree to the current heap forrest.
            root.AddSingleNode(newNode);

            return(newNode);
        }
Esempio n. 7
0
        public void Decrease(FibNode <T> payload, int newWeigth)
        {
            Debug.Assert(newWeigth <= payload.Weight);

            payload.Weight = newWeigth;
            UpdateMinimum(payload);

            if (payload.Parent == null)
            {
                return;
            }
            if (payload.Parent.Weight < payload.Weight)
            {
                return;
            }

            Cut(payload);
        }
Esempio n. 8
0
        private void Cut(FibNode <T> payload)
        {
            var parent = payload.Parent;

            // Cut the current node from it's parent and add it to the current heap forrest.
            parent.Children.RemoveChild(payload);
            root.AddSingleNode(payload);

#if !SIMPLE // If not simple, continue with marking & cuting
            payload.Marked = false;

            if (parent.Marked)
            {
                Cut(parent);
            }
            else if (parent.Parent != null)
            {
                parent.Marked = true;
            }
#endif
        }
Esempio n. 9
0
 /// <summary>
 /// Connects a single FibNode<T> to the current CyclicForrest.
 /// </summary>
 internal void AddSingleNode(FibNode <T> newNode) => ConnectToCurrentCyclicList(1, newNode);
Esempio n. 10
0
 public CyclicForrest(FibNode <T> firstChild, uint rank)
 {
     FirstChild = firstChild;
     Rank       = rank;
 }
Esempio n. 11
0
        private void Consolidate()
        {
            if (root.IsEmpty)
            {
                Debug.Assert(numberOfElements == 0);
                return;
            }

            // The maximum rank is log2(numberOfElements). +1 because the array is 0-based.
            var n = CurrMaxRank;

            FibNode <T>[] trees = new FibNode <T> [n];

            // Create trees for a new heap forrest from the old heap forrest
            {
                var currTree = root.FirstChild;
                do
                {
                    var nextNode = currTree.NextSibling;
                    ProcessTree(trees, currTree);
                    currTree = nextNode;
                } while (currTree != root.FirstChild);
            }

            // Create new heap forrest from the newly created trees with unique ranks
            {
                uint        newHeapRank     = 0;
                FibNode <T> newHeapRoot     = null;
                FibNode <T> lastNewHeapNode = null;

                for (int i = 0; i < trees.Length; i++)
                {
                    FibNode <T> newTree = trees[i];
                    if (newTree == null)
                    {
                        continue;
                    }

                    AddTreeToNewHeap(ref newHeapRank, ref newHeapRoot, ref lastNewHeapNode, newTree);
                }

                lastNewHeapNode.NextSibling = newHeapRoot;
                newHeapRoot.PreviousSibling = lastNewHeapNode;

                root = new CyclicForrest <T>(newHeapRoot, newHeapRank);
            }

            Debug.Assert(root.CheckChildren());

            //
            // Below are only local functions. They are not inlined because I believe it's more readable this way since they all
            // .. represent a standalone functionality. Others might disagree with that assesment, however.
            //

            // Connects a new tree to a heap forrest that is just being build
            void AddTreeToNewHeap(ref uint rank, ref FibNode <T> firstNode, ref FibNode <T> lastNode, FibNode <T> tree)
            {
                rank++;

                tree.Parent = null;
                tree.Marked = false;

                UpdateMinimum(tree);

                if (firstNode == null)
                {
                    firstNode = tree;
                }
                else
                {
                    lastNode.NextSibling = tree;
                    tree.PreviousSibling = lastNode;
                }

                lastNode = tree;
            }

            // Takes a tree and tries to add it to a rank-indexed tree array. If there is more than
            // ...one tree with the same rank it merges them and processes the newly created tree.
            // While recursion might seeem as a problem it can't be deeper than the maximum rank possible (with each
            // ...level the rank of currently processed tree increases by one) which is log2(number of elements).
            void ProcessTree(FibNode <T>[] treesArray, FibNode <T> treeBeingAdded)
            {
                uint currRank  = treeBeingAdded.Children.Rank;
                var  otherTree = treesArray[currRank];

                if (otherTree == null)
                {
                    treesArray[currRank] = treeBeingAdded;
                }
                else
                {
                    // Remove the tree the currently processed one will get merged with
                    treesArray[currRank] = null;

                    var lighterTree = treeBeingAdded.Weight < otherTree.Weight ? treeBeingAdded : otherTree;
                    var heavierTree = treeBeingAdded.Weight < otherTree.Weight ? otherTree : treeBeingAdded;

                    FibNode <T> newTree = MergeTrees(lighterTree, heavierTree);

                    Debug.Assert(currRank + 1 == newTree.Children.Rank);
                    Debug.Assert(newTree.Children.Rank <= CurrMaxRank);
                    ProcessTree(treesArray, newTree);
                }
            }

            FibNode <T> MergeTrees(FibNode <T> lighterTree, FibNode <T> heavierTree)
            {
                Debug.Assert(lighterTree.Children.Rank == heavierTree.Children.Rank);
                Debug.Assert(lighterTree.Weight <= heavierTree.Weight && heavierTree != lighterTree);

                logger.AddValue(1);

                // Remove the heavier tree from its original context and add it as a new sibling under the lighter tree.
                heavierTree.ResetSiblingsAndParentToATreeState();
                heavierTree.Parent = lighterTree;
                lighterTree.Children.AddSingleNode(heavierTree);

                Debug.Assert(lighterTree.Children.Rank <= CurrMaxRank);

                Debug.Assert(lighterTree.Children.CheckChildren());
                Debug.Assert(!lighterTree.Children.IsEmpty);

                return(lighterTree);
            }
        }