/// /// Copyright (c) 2020 Sensus Slovensko a.s. /// using System; using System.Collections.Generic; namespace SchematicDrawing { public class MinHeap { GNode[] heap; /// Minimum heap, a binary tree in form of an array int heapSize; /// Heap size (not necessarily a size of the array heap[]) /// /// Constructor /// public MinHeap() { heap = null; heapSize = 0; } /// /// Reset nodes and build the initial minimum heap tree. /// /// First node on the list is the start node (mostly the main water tank), /// followed by 'secondaryStartNodesCount' secondary start nodes (typically /// tanks above scales), followed by all remaining nodes of the drawing. /// In this way the heap is heapified from the beginning. /// /// Graph nodes /// Number of secondary start nodes public void ResetAndBuild(IList nodes, int secondaryStartNodesCount) { if (nodes == null || nodes.Count == 0) return; if (heapSize != nodes.Count) { heapSize = nodes.Count; heap = new GNode[nodes.Count]; } heap[0] = nodes[0].Reset(0, 0); for (int i = 1; i <= secondaryStartNodesCount; i++) { heap[i] = nodes[i].Reset(i, Const.SecondaryStart); } for (int i = secondaryStartNodesCount + 1; i < nodes.Count; i++) { heap[i] = nodes[i].Reset(i, int.MaxValue); } } /// /// Returns the node with minimal distance at the top of the heap binary tree. /// This node is removed from the heap, replaced by the last node and the heap is 'Heapified'. /// /// Node with minimal distance public GNode ExtractMinNode() { GNode minNode = heap[0]; if (--heapSize > 0) { heap[0] = heap[heapSize]; /// Swap with the last one heap[0].HeapIx = 0; heap[heapSize] = minNode; SiftDown(0); /// Heapify the heap, sift down the swapped (formerly the last) item } return minNode; } /// /// Sift up the node in the minimum heap binary tree. /// Function is called when distance of a node in the graph is updated. /// As the distance is always decreased, the node sifts up in the tree. /// /// Index of the node to sift up public void SiftUp(int heapIx) { if (heapIx == 0) return; int parentIx = (heapIx - 1) / 2; if (heap[heapIx].Dist < heap[parentIx].Dist) { SwapNodes(heapIx, parentIx); SiftUp(parentIx); } } /// /// Sift down the node in the minimum heap binary tree. /// Function is called when node at the top of the tree is extracted and replaced /// by the last node. This last node is then sift down according to its distance. /// /// Index of the node to sift down void SiftDown(int heapIx) { int leftIx = 2 * heapIx + 1; if (leftIx < heapSize) { int minIx = heapIx; if (heap[leftIx].Dist < heap[minIx].Dist) { minIx = leftIx; } int rightIx = 2 * heapIx + 2; if (rightIx < heapSize && heap[rightIx].Dist < heap[minIx].Dist) { minIx = rightIx; } if (minIx != heapIx) { SwapNodes(heapIx, minIx); SiftDown(minIx); } } } /// /// Swap two nodes in the minimum heap binary tree. /// /// Index of the 1st node /// Index of the 2nd node void SwapNodes(int ix1, int ix2) { GNode swap = heap[ix1]; heap[ix1] = heap[ix2]; heap[ix1].HeapIx = ix1; heap[ix2] = swap; heap[ix2].HeapIx = ix2; } } }