2024-12-14 18:27:59 +08:00

292 lines
7.6 KiB
C#

/****************************************************************************
* Copyright (c) 2017 snowcold
* Copyright (c) 2017 liangxie UNDER MIT LICENSE
*
* https://qframework.cn
* https://github.com/liangxiegame/QFramework
* https://gitee.com/liangxiegame/QFramework
****************************************************************************/
namespace QFramework
{
using System;
public enum BinaryHeapBuildMode
{
kNLog = 1,
kN = 2,
}
public enum BinaryHeapSortMode
{
kMin = 0,
kMax = 1,
}
//优先队列&二叉堆
public class BinaryHeap<T> where T : IBinaryHeapElement
{
protected T[] mArray;
protected float mGrowthFactor = 1.6f;
protected int mLastChildIndex; //最后子节点的位置
protected BinaryHeapSortMode mSortMode;
public BinaryHeap(int minSize, BinaryHeapSortMode sortMode)
{
mSortMode = sortMode;
mArray = new T[minSize];
mLastChildIndex = 0;
}
#region
#region
public void Clear()
{
mArray = new T[10];
mLastChildIndex = 0;
}
#endregion
#region
public void Insert(T element)
{
if (element == null)
{
throw new NullReferenceException("BinaryHeap Not Support Insert Null Object");
}
int index = ++mLastChildIndex;
if (index == mArray.Length)
{
ResizeArray();
}
mArray[index] = element;
ProcolateUp(index);
}
#endregion
#region
public T Pop()
{
if (mLastChildIndex < 1)
{
return default(T);
}
T result = mArray[1];
mArray[1] = mArray[mLastChildIndex--];
ProcolateDown(1);
return result;
}
public T Top()
{
if (mLastChildIndex < 1)
{
return default(T);
}
return mArray[1];
}
#endregion
#region
public void RebuildAtIndex(int index)
{
if (index > mLastChildIndex)
{
return;
}
//1.首先找父节点,是否比父节点小,如果满足则上浮,不满足下沉
var element = mArray[index];
int parentIndex = index >> 1;
if (parentIndex > 0)
{
if (mSortMode == BinaryHeapSortMode.kMin)
{
if (element.SortScore < mArray[parentIndex].SortScore)
{
ProcolateUp(index);
}
else
{
ProcolateDown(index);
}
}
else
{
if (element.SortScore > mArray[parentIndex].SortScore)
{
ProcolateUp(index);
}
else
{
ProcolateDown(index);
}
}
}
else
{
ProcolateDown(index);
}
}
private void SortAsCurrentMode()
{
int startChild = mLastChildIndex >> 1;
for (int i = startChild; i > 0; --i)
{
ProcolateDown(i);
}
}
#endregion
#region
protected void ResizeArray(int newSize = -1)
{
if (newSize < 0)
{
newSize = System.Math.Max(mArray.Length + 4, (int) System.Math.Round(mArray.Length * mGrowthFactor));
}
if (newSize > 1 << 30)
{
throw new System.Exception(
"Binary Heap Size really large (2^18). A heap size this large is probably the cause of pathfinding running in an infinite loop. " +
"\nRemove this check (in BinaryHeap.cs) if you are sure that it is not caused by a bug");
}
T[] tmp = new T[newSize];
for (int i = 0; i < mArray.Length; i++)
{
tmp[i] = mArray[i];
}
mArray = tmp;
}
//上浮:空穴思想
protected void ProcolateUp(int index)
{
var element = mArray[index];
if (element == null)
{
return;
}
float sortScore = element.SortScore;
int parentIndex = index >> 1;
if (mSortMode == BinaryHeapSortMode.kMin)
{
while (parentIndex >= 1 && sortScore < mArray[parentIndex].SortScore)
{
mArray[index] = mArray[parentIndex];
mArray[index].HeapIndex = index;
index = parentIndex;
parentIndex = index >> 1;
}
}
else
{
while (parentIndex >= 1 && sortScore > mArray[parentIndex].SortScore)
{
mArray[index] = mArray[parentIndex];
mArray[index].HeapIndex = index;
index = parentIndex;
parentIndex = index >> 1;
}
}
mArray[index] = element;
mArray[index].HeapIndex = index;
}
protected void ProcolateDown(int index)
{
var element = mArray[index];
if (element == null)
{
return;
}
int childIndex = index << 1;
if (mSortMode == BinaryHeapSortMode.kMin)
{
while (childIndex <= mLastChildIndex)
{
if (childIndex != mLastChildIndex)
{
if (mArray[childIndex + 1].SortScore < mArray[childIndex].SortScore)
{
childIndex = childIndex + 1;
}
}
if (mArray[childIndex].SortScore < element.SortScore)
{
mArray[index] = mArray[childIndex];
mArray[index].HeapIndex = index;
}
else
{
break;
}
index = childIndex;
childIndex = index << 1;
}
}
else
{
while (childIndex <= mLastChildIndex)
{
if (childIndex != mLastChildIndex)
{
if (mArray[childIndex + 1].SortScore > mArray[childIndex].SortScore)
{
childIndex = childIndex + 1;
}
}
if (mArray[childIndex].SortScore > element.SortScore)
{
mArray[index] = mArray[childIndex];
mArray[index].HeapIndex = index;
}
else
{
break;
}
index = childIndex;
childIndex = index << 1;
}
}
mArray[index] = element;
mArray[index].HeapIndex = index;
}
#endregion
#endregion
}
}