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); }
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); } }