示例#1
0
 /// <summary>
 /// Merges another CyclicForrest into the current one.
 /// </summary>
 internal void AddChildren(CyclicForrest <T> newChildren) => ConnectToCurrentCyclicList(newChildren.Rank, newChildren.FirstChild);
示例#2
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);
            }
        }