using System.Linq;
using System;
namespace BF
{
///
/// 最小二叉堆
///
public class BFBinaryHeap where T : IComparable
{
T[] items;
public int Count { get; private set; }
public BFBinaryHeap() : this(50) { }
public BFBinaryHeap(int size)
{
if (size < 0)
throw new IndexOutOfRangeException();
items = new T[size];
}
public void Enqueue(T value)
{
if (Count == items.Length)
Resize(Count * 2);
items[Count] = value;
++Count;
UpAdjust(Count - 1);
}
public T Dequeue()
{
if (Count == 0)
throw new InvalidOperationException();
var result = items[0];
--Count;
if (Count > 0)
{
items[0] = items[Count];
items[Count] = default;
DownAdjust();
}
return result;
}
public T RemoveAtEnd()
{
if (Count == 0)
throw new InvalidOperationException();
var result = items[Count - 1];
items[Count - 1] = default;
--Count;
return result;
}
void Resize(int newSize)
{
var temp = new T[newSize];
Array.Copy(items, 0, temp, 0, Count);
items = temp;
}
///
/// 下沉调整 用于删除堆顶
///
void DownAdjust()
{
int parent = 0;
int left = (parent * 2) + 1; // left index
while (left < Count)
{
int right = left + 1; // right index (parent + 1) * 2
var t1 = items[right];
var t2 = items[left];
int min = (right < Count && t1.CompareTo(t2) < 0) ? right : left;
t1 = items[min];
t2 = items[parent];
if (t1.CompareTo(t2) < 0)
{
items[parent] = t1;
items[min] = t2;
parent = min;
left = (parent * 2) + 1;
}
else
{
break;
}
}
}
///
/// 上浮调整 用于插入
///
void UpAdjust(int index)
{
while (index > 0)
{
int parent = (index - 1) / 2; // parent index
var t1 = items[index];
var t2 = items[parent];
if (t1.CompareTo(t2) < 0)
{
items[index] = t2;
items[parent] = t1;
}
else
{
break;
}
index = parent;
}
}
///
/// 如果t的value变小了 尝试上浮调整
///
public void TryUpAdjust(T t)
{
int index = GetIndex(t);
UpAdjust(index);
}
int GetIndex(T value)
{
int Count = items.Length;
for (int i = 0; i < Count; i++)
{
if (ReferenceEquals(items[i], value))
return i;
}
return -1;
}
}
}