/// <summary> /// Moves a node up in the tree to restore heap order. /// </summary> /// <param name="node">The node to be moved up.</param> private void MoveUp(ArrayHeapNode <TKey, TValue> node) { var i = node.Index; // Instead of swapping items all the way to the root, we will perform // a similar optimization as in the insertion sort. while (i > 0) { var parentIndex = this.GetParentIndex(i); var parent = this.nodes[parentIndex]; if (this.Comparer.Compare(node.Key, parent.Key) < 0) { this.PutAt(parent, i); i = parentIndex; } else { break; } } this.PutAt(node, i); }
/// <inheritdoc cref="IHeap{TKey,TValue}.Add"/> public override ArrayHeapNode <TKey, TValue> Add(TKey key, TValue value) { // Add node at the end var node = new ArrayHeapNode <TKey, TValue>(key, value, this.Count); this.nodes.Add(node); // Restore the heap order this.MoveUp(node); return(node); }
/// <summary> /// Moves a node down in the tree to restore heap order. /// </summary> /// <param name="node">The node to be moved down.</param> private void MoveDown(ArrayHeapNode <TKey, TValue> node) { // The node to move down will not actually be swapped every time. // Rather, values on the affected path will be moved up, thus leaving a free spot // for this value to drop in. Similar optimization as in the insertion sort. var index = node.Index; int i; while ((i = this.GetFirstChildIndex(index)) < this.Count) { // Check if the current node (pointed by 'index') should really be extracted // first, or maybe one of its children should be extracted earlier. var topChild = this.nodes[i]; var childrenIndexesLimit = Math.Min(i + this.Arity, this.Count); while (++i < childrenIndexesLimit) { var child = this.nodes[i]; if (this.Comparer.Compare(child.Key, topChild.Key) < 0) { topChild = child; } } // In case no child needs to be extracted earlier than the current node, // there is nothing more to do - the right spot was found. if (this.Comparer.Compare(node.Key, topChild.Key) <= 0) { break; } // Move the top child up by one node and now investigate the // node that was considered to be the top child (recursive). var topChildIndex = topChild.Index; this.PutAt(topChild, index); index = topChildIndex; } this.PutAt(node, index); }
/// <inheritdoc cref="IHeap{TKey,TValue}.Remove"/> public override TValue Remove(ArrayHeapNode <TKey, TValue> node) { if (node == null) { throw new ArgumentNullException(nameof(node)); } // The idea is to replace the specified node by the very last // node and shorten the array by one. var lastNode = this.nodes[this.Count - 1]; this.nodes.RemoveAt(lastNode.Index); // In case we wanted to remove the node that was the last one, // we are done. if (node == lastNode) { return(node.Value); } // Our last node was erased from the array and needs to be // inserted again. Of course, we will overwrite the node we // wanted to remove. After that operation, we will need // to restore the heap property (in general). var relation = this.Comparer.Compare(lastNode.Key, node.Key); this.PutAt(lastNode, node.Index); if (relation < 0) { this.MoveUp(lastNode); } else { this.MoveDown(lastNode); } return(node.Value); }
/// <inheritdoc cref="IHeap{TKey,TValue}.Update"/> public override void Update(ArrayHeapNode <TKey, TValue> node, TKey key) { if (node == null) { throw new ArgumentNullException(nameof(node)); } var relation = this.Comparer.Compare(key, node.Key); node.Key = key; if (relation < 0) { this.MoveUp(node); } else { this.MoveDown(node); } }
/// <summary> /// Puts a node at the specified index. /// </summary> private void PutAt(ArrayHeapNode <TKey, TValue> node, int index) { node.Index = index; this.nodes[index] = node; }