WuhuIslandTesting/Library/PackageCache/com.unity.services.core@1.6.0/Runtime/Scheduler/MinimumBinaryHeap.cs

198 lines
5.3 KiB
C#
Raw Normal View History

2025-01-07 02:06:59 +01:00
using System;
using System.Collections.Generic;
namespace Unity.Services.Core.Scheduler.Internal
{
abstract class MinimumBinaryHeap
{
internal const float IncreaseFactor = 1.5f;
internal const float DecreaseFactor = 2.0f;
}
class MinimumBinaryHeap<T> : MinimumBinaryHeap
{
readonly IComparer<T> m_Comparer;
readonly int m_MinimumCapacity;
T[] m_HeapArray;
internal IReadOnlyList<T> HeapArray => m_HeapArray;
public int Count { get; private set; }
public T Min => m_HeapArray[0];
public MinimumBinaryHeap(int minimumCapacity = 10)
: this(Comparer<T>.Default, minimumCapacity) {}
public MinimumBinaryHeap(IComparer<T> comparer, int minimumCapacity = 10)
: this(null, comparer, minimumCapacity) {}
internal MinimumBinaryHeap(ICollection<T> collection, IComparer<T> comparer, int minimumCapacity = 10)
{
if (minimumCapacity <= 0)
{
throw new ArgumentException("capacity must be more than 0");
}
m_MinimumCapacity = minimumCapacity;
m_Comparer = comparer;
Count = collection?.Count ?? 0;
var startSize = Math.Max(Count, minimumCapacity);
m_HeapArray = new T[startSize];
if (collection is null)
return;
// Reset count since we insert all items.
Count = 0;
foreach (var item in collection)
{
Insert(item);
}
}
public void Insert(T data)
{
IncreaseHeapCapacityWhenFull();
var dataPos = Count;
m_HeapArray[Count] = data;
Count++;
while (dataPos != 0
&& m_Comparer.Compare(m_HeapArray[dataPos], m_HeapArray[Parent(dataPos)]) < 0)
{
Swap(ref m_HeapArray[dataPos], ref m_HeapArray[Parent(dataPos)]);
dataPos = Parent(dataPos);
}
}
void IncreaseHeapCapacityWhenFull()
{
if (Count != m_HeapArray.Length)
{
return;
}
var newCapacity = (int)Math.Ceiling(Count * IncreaseFactor);
var newHeapArray = new T[newCapacity];
Array.Copy(m_HeapArray, newHeapArray, Count);
m_HeapArray = newHeapArray;
}
public void Remove(T data)
{
var key = GetKey(data);
if (key < 0)
return;
while (key != 0)
{
Swap(ref m_HeapArray[key], ref m_HeapArray[Parent(key)]);
key = Parent(key);
}
ExtractMin();
}
public T ExtractMin()
{
if (Count <= 0)
{
throw new InvalidOperationException("Can not ExtractMin: BinaryHeap is empty.");
}
var data = m_HeapArray[0];
if (Count == 1)
{
Count--;
m_HeapArray[0] = default;
return data;
}
Count--;
m_HeapArray[0] = m_HeapArray[Count];
m_HeapArray[Count] = default;
MinHeapify();
DecreaseHeapCapacityWhenSpare();
return data;
}
void DecreaseHeapCapacityWhenSpare()
{
var spareThreshold = (int)Math.Ceiling(m_HeapArray.Length / DecreaseFactor);
if (Count <= m_MinimumCapacity
|| Count > spareThreshold)
{
return;
}
var newHeapArray = new T[Count];
Array.Copy(m_HeapArray, newHeapArray, Count);
m_HeapArray = newHeapArray;
}
int GetKey(T data)
{
var key = -1;
for (var i = 0; i < Count; i++)
{
if (m_HeapArray[i].Equals(data))
{
key = i;
break;
}
}
return key;
}
void MinHeapify()
{
int key;
var smallest = 0;
do
{
key = smallest;
UpdateSmallestKey();
if (smallest == key)
{
return;
}
Swap(ref m_HeapArray[key], ref m_HeapArray[smallest]);
}
while (smallest != key);
void UpdateSmallestKey()
{
smallest = key;
var leftKey = LeftChild(key);
var rightKey = RightChild(key);
UpdateSmallestIfCandidateIsSmaller(leftKey);
UpdateSmallestIfCandidateIsSmaller(rightKey);
}
void UpdateSmallestIfCandidateIsSmaller(int candidate)
{
if (candidate >= Count
|| m_Comparer.Compare(m_HeapArray[candidate], m_HeapArray[smallest]) >= 0)
{
return;
}
smallest = candidate;
}
}
static void Swap(ref T lhs, ref T rhs) => (lhs, rhs) = (rhs, lhs);
static int Parent(int key) => (key - 1) / 2;
static int LeftChild(int key) => 2 * key + 1;
static int RightChild(int key) => 2 * key + 2;
}
}