using System; using System.Collections; using System.Collections.Generic; namespace KDTree { /// /// A MinHeap is a smallest-first queue based around a binary heap so it is quick to insert / remove items. /// /// The type of data this MinHeap stores. /// This is based on this: https://bitbucket.org/rednaxela/knn-benchmark/src/tip/ags/utils/dataStructures/trees/thirdGenKD/ public class MinHeap { /// /// The default size for a min heap. /// private static int DEFAULT_SIZE = 64; /// /// The data array. This stores the data items in the heap. /// private T[] tData; /// /// The key array. This determines how items are ordered. Smallest first. /// private double[] tKeys; /// /// Create a new min heap with the default capacity. /// public MinHeap() : this(DEFAULT_SIZE) { } /// /// Create a new min heap with a given capacity. /// /// public MinHeap(int iCapacity) { this.tData = new T[iCapacity]; this.tKeys = new double[iCapacity]; this.Capacity = iCapacity; this.Size = 0; } /// /// The number of items in this queue. /// public int Size { get; private set; } /// /// The amount of space in this queue. /// public int Capacity { get; private set; } /// /// Insert a new element. /// /// The key which represents its position in the priority queue (ie. distance). /// The value to be stored at the key. public void Insert(double key, T value) { // If we need more room, double the space. if (Size >= Capacity) { // Calcualte the new capacity. Capacity *= 2; // Copy the data array. var newData = new T[Capacity]; Array.Copy(tData, newData, tData.Length); tData = newData; // Copy the key array. var newKeys = new double[Capacity]; Array.Copy(tKeys, newKeys, tKeys.Length); tKeys = newKeys; } // Insert new value at the end tData[Size] = value; tKeys[Size] = key; SiftUp(Size); Size++; } /// /// Remove the smallest element. /// public void RemoveMin() { if (Size == 0) throw new Exception(); Size--; tData[0] = tData[Size]; tKeys[0] = tKeys[Size]; tData[Size] = default(T); SiftDown(0); } /// /// Get the data stored at the minimum element. /// public T Min { get { if (Size == 0) throw new Exception(); return tData[0]; } } /// /// Get the key which represents the minimum element. /// public double MinKey { get { if (Size == 0) throw new Exception(); return tKeys[0]; } } /// /// Bubble a child item up the tree. /// /// private void SiftUp(int iChild) { // For each parent above the child, if the parent is smaller then bubble it up. for (int iParent = (iChild - 1) / 2; iChild != 0 && tKeys[iChild] < tKeys[iParent]; iChild = iParent, iParent = (iChild - 1) / 2) { T kData = tData[iParent]; double dDist = tKeys[iParent]; tData[iParent] = tData[iChild]; tKeys[iParent] = tKeys[iChild]; tData[iChild] = kData; tKeys[iChild] = dDist; } } /// /// Bubble a parent down through the children so it goes in the right place. /// /// The index of the parent. private void SiftDown(int iParent) { // For each child. for (int iChild = iParent * 2 + 1; iChild < Size; iParent = iChild, iChild = iParent * 2 + 1) { // If the child is larger, select the next child. if (iChild + 1 < Size && tKeys[iChild] > tKeys[iChild + 1]) iChild++; // If the parent is larger than the largest child, swap. if (tKeys[iParent] > tKeys[iChild]) { // Swap the points T pData = tData[iParent]; double pDist = tKeys[iParent]; tData[iParent] = tData[iChild]; tKeys[iParent] = tKeys[iChild]; tData[iChild] = pData; tKeys[iChild] = pDist; } // TODO: REMOVE THE BREAK else { break; } } } } }