public BinomialNode(T value, BinomialNode <T> parent, BinomialNode <T> sibling, BinomialNode <T> child) { Value = value; Parent = parent; Sibling = sibling; Child = child; }
/// <summary> /// Removes and returns the min element of the <see cref="BinomialMinHeap{T}"/>. /// </summary> /// <returns>Returns the min element which was removed from the <see cref="BinomialMinHeap{T}"/>.</returns> public T PopMin() { if (IsEmpty) { throw new InvalidOperationException("Heap is empty!"); } BinomialNode min = head; // min node BinomialNode minPrev = null; // node before the min node BinomialNode current = min.Sibling; // current node in the traversal BinomialNode last = min; // the last traversed node while (current != null) { if (current.Value.CompareTo(min.Value) <= 0) { min = current; minPrev = last; } last = current; current = current.Sibling; } // Saving count because when removing the binomial tree root // the current heap is merged with a new heap with unknown // number of elements var oldCount = Count; RemoveBinomialTreeRoot(min, minPrev); Count = oldCount - 1; return(min.Value); }
/************************************************************************************************/ /** PRIVATE HELPER FUNCTIONS */ /// <summary> /// Removes root of tree at he specified index. /// </summary> private void _removeAtIndex(int minIndex) { // Get the deletedTree // The min-root lies at _forest[minIndex] BinomialNode <T> deletedTreeRoot = _forest[minIndex].Child; // Exit if there was no children under old-min-root if (deletedTreeRoot == null) { return; } // CONSTRUCT H'' (double-prime) BinomialMinHeap <T> deletedForest = new BinomialMinHeap <T>(); deletedForest._forest.Resize(minIndex + 1); deletedForest._size = (1 << minIndex) - 1; for (int i = (minIndex - 1); i >= 0; --i) { deletedForest._forest[i] = deletedTreeRoot; deletedTreeRoot = deletedTreeRoot.Sibling; deletedForest._forest[i].Sibling = null; } // CONSTRUCT H' (single-prime) _forest[minIndex] = null; _size = deletedForest._size + 1; Merge(deletedForest); // Decrease the size --_size; }
/// <summary> /// Removes the tree root of a binomial tree given the tree root and the <see cref="BinomialNode"/> before it. /// </summary> /// <param name="treeRoot">The root node of the binomial tree.</param> /// <param name="previous">The <see cref="BinomialNode"/> before the tree root.</param> internal void RemoveBinomialTreeRoot(BinomialNode treeRoot, BinomialNode previous) { if (treeRoot == head) { head = head.Sibling; } else { if (previous != null) { previous.Sibling = treeRoot.Sibling; } } // Reversing order of root children and creating a new heap BinomialNode newHead = null; var child = treeRoot.Child; while (child != null) { var next = child.Sibling; child.Sibling = newHead; child.Parent = null; newHead = child; child = next; } var newHeap = new BinomialMinHeap <T>(newHead); Merge(newHeap); }
/// <summary> /// Adds an element to the <see cref="BinomialMinHeap{T}"/>. /// </summary> /// <param name="value">The value to add.</param> public void Add(T value) { var newNode = new BinomialNode(value); var tempHeap = new BinomialMinHeap <T>(newNode); Merge(tempHeap); }
/// <summary> /// Merge two binomial trees to a new tree of higher order, given the roots of the trees. /// </summary> /// <param name="smallerNode">The <see cref="BinomialNode"/> with the smaller value.</param> /// <param name="biggerNode">The <see cref="BinomialNode"/> with the bigger value.</param> internal void MergeBinomialTrees(BinomialNode smallerNode, BinomialNode biggerNode) { biggerNode.Parent = smallerNode; biggerNode.Sibling = smallerNode.Child; smallerNode.Child = biggerNode; smallerNode.Degree++; }
/// <summary> /// Clones a tree, given it's root node. /// </summary> private BinomialNode <T> _cloneTree(BinomialNode <T> treeRoot) { if (treeRoot == null) { return(null); } return(new BinomialNode <T>() { Value = treeRoot.Value, Child = _cloneTree(treeRoot.Child), Sibling = _cloneTree(treeRoot.Sibling) }); }
/// <summary> /// Combines two trees and returns the new tree root node. /// </summary> private BinomialNode <T> _combineTrees(BinomialNode <T> firstTreeRoot, BinomialNode <T> secondTreeRoot) { if (firstTreeRoot == null || secondTreeRoot == null) { throw new ArgumentNullException("Either one of the nodes or both are null."); } if (secondTreeRoot.Value.IsLessThan(firstTreeRoot.Value)) { return(_combineTrees(secondTreeRoot, firstTreeRoot)); } secondTreeRoot.Sibling = firstTreeRoot.Child; firstTreeRoot.Child = secondTreeRoot; secondTreeRoot.Parent = firstTreeRoot; return(firstTreeRoot); }
/// <summary> /// Merges the elements of another heap with this heap. /// </summary> public void Merge(BinomialMinHeap <T> otherHeap) { // Avoid aliasing problems if (this == otherHeap) { return; } // Avoid null or empty cases if (otherHeap == null || otherHeap.IsEmpty()) { return; } BinomialNode <T> carryNode = null; _size = _size + otherHeap._size; // One capacity-change step if (_size > _forest.Count) { int newSize = Math.Max(this._forest.Count, otherHeap._forest.Count) + 1; this._forest.Resize(newSize); } for (int i = 0, j = 1; j <= _size; i++, j *= 2) { BinomialNode <T> treeRoot1 = (_forest.IsEmpty == true ? null : _forest[i]); BinomialNode <T> treeRoot2 = (i < otherHeap._forest.Count ? otherHeap._forest[i] : null); int whichCase = (treeRoot1 == null ? 0 : 1); whichCase += (treeRoot2 == null ? 0 : 2); whichCase += (carryNode == null ? 0 : 4); switch (whichCase) { /*** SINGLE CASES ***/ case 0: /* No trees */ case 1: /* Only this */ break; case 2: /* Only otherHeap */ this._forest[i] = treeRoot2; otherHeap._forest[i] = null; break; case 4: /* Only carryNode */ this._forest[i] = carryNode; carryNode = null; break; /*** BINARY CASES ***/ case 3: /* this and otherHeap */ carryNode = _combineTrees(treeRoot1, treeRoot2); this._forest[i] = otherHeap._forest[i] = null; break; case 5: /* this and carryNode */ carryNode = _combineTrees(treeRoot1, carryNode); this._forest[i] = null; break; case 6: /* otherHeap and carryNode */ carryNode = _combineTrees(treeRoot2, carryNode); otherHeap._forest[i] = null; break; case 7: /* all the nodes */ this._forest[i] = carryNode; carryNode = _combineTrees(treeRoot1, treeRoot2); otherHeap._forest[i] = null; break; } //end-switch } //end-for // Clear otherHeap otherHeap.Clear(); }
/// <summary> /// Creates a new instance of the <see cref="BinomialMinHeap{T}"/> class, with the specified node as head. /// </summary> /// <param name="head">The head node.</param> internal BinomialMinHeap(BinomialNode head) { this.head = head; Count = 1; }
/// <summary> /// Removes all elements from the <see cref="BinomialMinHeap{T}"/>. /// </summary> public void Clear() { head = null; Count = 0; }
/// <summary> /// Merges the elements of the <see cref="BinomialMinHeap{T}"/> with the other given <see cref="BinomialMinHeap{T}"/>. The other <see cref="BinomialMinHeap{T}"/> is cleared after the merging. /// </summary> /// <param name="otherMinHeap">The other <see cref="BinomialMinHeap{T}"/> used for merging.</param> public void Merge(BinomialMinHeap <T> otherMinHeap) { // if the given heap has no elements if (otherMinHeap.head == null) { return; } // if this heap is empty if (head == null) { // copy the head of the other heap and clear it head = otherMinHeap.head; Count = otherMinHeap.Count; otherMinHeap.Clear(); return; } // if both heaps have elements BinomialNode newHead; var firstHeapNextNode = head; var secondHeapNextNode = otherMinHeap.head; // Set the heap head of lower order as the new head if (head.Degree <= otherMinHeap.head.Degree) { newHead = head; firstHeapNextNode = firstHeapNextNode.Sibling; } else { newHead = otherMinHeap.head; secondHeapNextNode = secondHeapNextNode.Sibling; } var curNode = newHead; // Iterating over the roots of the binomial trees of the heaps and // sorting them by order(binomial tree order) while (firstHeapNextNode != null && secondHeapNextNode != null) { if (firstHeapNextNode.Degree <= secondHeapNextNode.Degree) { curNode.Sibling = firstHeapNextNode; firstHeapNextNode = firstHeapNextNode.Sibling; } else { curNode.Sibling = secondHeapNextNode; secondHeapNextNode = secondHeapNextNode.Sibling; } curNode = curNode.Sibling; } if (firstHeapNextNode != null) { curNode.Sibling = firstHeapNextNode; } else { curNode.Sibling = secondHeapNextNode; } head = newHead; // After the new head links to the binomial tree roots sorted by order // we have to leave at most one tree of each order. We can do this by merging every // two trees of order k to a new tree of order k + 1 BinomialNode previous = null; BinomialNode current = newHead; BinomialNode next = newHead.Sibling; while (next != null) { // if the order of the trees is different // or we have 3 trees of the same order we continue onwards. // Having 3 trees of order k. We can leave one with order k and merge // the next 2 to create a tree of order k + 1 // Note: It is not possible to have more than 3 trees of order k, // because a heap has at most one tree of each order. So merging two heaps // we get maximum of two trees with the same order and having 2 trees // of order k and 2 trees of order k + 1. We merge the 2 trees of order k // to a tree of order k + 1 and now we have 3 trees of order k + 1(leaving one // and merging the other 2). So having 4 trees of same order is not possible if (current.Degree != next.Degree || ((next.Sibling?.Degree ?? -1) == current.Degree)) { previous = current; current = next; } else// if we need to merge 2 trees of same order { // if the current node is smaller than or equal to the next if (current.Value.CompareTo(next.Value) <= 0) { current.Sibling = next.Sibling; MergeBinomialTrees(smallerNode: current, biggerNode: next); } else// if the current is bigger that the next { // we set the previous node link to this one if (previous == null) { newHead = next; } else { previous.Sibling = next; } MergeBinomialTrees(smallerNode: next, biggerNode: current); current = next; } } // Here current has became the next node, // so the new next node is the sibling of the current next = current.Sibling; } // At last we update the head and the count head = newHead; Count += otherMinHeap.Count; // We clear the other heap otherMinHeap.Clear(); }