You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

167 lines
3.6 KiB

using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
public class SimpleHeap<T> : IEnumerable<T>
{
const int ROOT_IDX = 0;
const int INVALID_IDX = -1;
T[] data = new T[0];
int count = 0;
Func<T, T, bool> m_compareFunc;
public int Count => count;
public SimpleHeap(Func<T, T, bool> compareFunc)
{
m_compareFunc = compareFunc;
}
public SimpleHeap(T[] collection, Func<T, T, bool> 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<T> GetEnumerator() => ((IEnumerable<T>)data).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}