using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; public class SimpleHeap : IEnumerable { const int ROOT_IDX = 0; const int INVALID_IDX = -1; T[] data = new T[0]; int count = 0; Func m_compareFunc; public int Count => count; public SimpleHeap(Func compareFunc) { m_compareFunc = compareFunc; } public SimpleHeap(T[] collection, Func compareFunc) { m_compareFunc = compareFunc; data = new T[collection.Length]; for (int i = 0; i < collection.Length; i++) { Push(collection[i]); } } public void Push(T value) { insertBack(value); climbUntilLimit(count - 1); } public T Pop() { if (IsEmpty()) return default; T result = data[ROOT_IDX]; swap(0, --count); fallUntilLimit(0); return result; } public T GetRootValue() { if (IsEmpty()) return default; return data[ROOT_IDX]; } public bool TryGetRootValue(out T value) { if (IsEmpty()) { value = default; return false; } value = data[ROOT_IDX]; return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsEmpty() => count == 0; [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Clear() => count = 0; void climbUntilLimit(int curIdx) { int parentIdx = getParentIdx(curIdx); if (parentIdx == INVALID_IDX) return; if (m_compareFunc(data[curIdx], data[parentIdx])) { swap(curIdx, parentIdx); climbUntilLimit(parentIdx); } else { return; } } void fallUntilLimit(int curIdx) { int leftChildIdx = getLeftChildIdx(curIdx); int rightChildIdx = getRightChildIdx(curIdx); int aptIdx = curIdx; if (leftChildIdx != INVALID_IDX && rightChildIdx != INVALID_IDX) { aptIdx = getAptIndex(leftChildIdx, rightChildIdx); aptIdx = getAptIndex(curIdx, aptIdx); } else if (leftChildIdx != INVALID_IDX) { aptIdx = getAptIndex(curIdx, leftChildIdx); } if (aptIdx == curIdx) { return; } swap(curIdx, aptIdx); fallUntilLimit(aptIdx); } void insertBack(T value) { if (count >= data.Length) Array.Resize(ref data, count + 1); data[count++] = value; } int getParentIdx(int curIdx) { if (curIdx == 0) return -1; return (int)((curIdx - 1) * 0.5f); } int getLeftChildIdx(int curIdx) { int result = curIdx * 2 + 1; if (result >= count) result = INVALID_IDX; return result; } int getRightChildIdx(int curIdx) { int result = curIdx * 2 + 2; if (result >= count) result = INVALID_IDX; return result; } int getAptIndex(int value1Index, int value2Index) => m_compareFunc(data[value1Index], data[value2Index]) ? value1Index : value2Index; void swap(int sourceIdx, int destinationIdx) { T tmp = data[sourceIdx]; data[sourceIdx] = data[destinationIdx]; data[destinationIdx] = tmp; } public IEnumerator GetEnumerator() => ((IEnumerable)data).GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); }