暂无描述
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

MinimumBinaryHeap.cs 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. using System;
  2. using System.Collections.Generic;
  3. namespace Unity.Services.Core.Scheduler.Internal
  4. {
  5. abstract class MinimumBinaryHeap
  6. {
  7. internal const float IncreaseFactor = 1.5f;
  8. internal const float DecreaseFactor = 2.0f;
  9. }
  10. class MinimumBinaryHeap<T> : MinimumBinaryHeap
  11. {
  12. /// <remarks>
  13. /// Members requiring thread safety:
  14. /// * <see cref="m_HeapArray"/>.
  15. /// * <see cref="Count"/>.
  16. /// </remarks>
  17. readonly object m_Lock = new object();
  18. readonly IComparer<T> m_Comparer;
  19. readonly int m_MinimumCapacity;
  20. T[] m_HeapArray;
  21. internal IReadOnlyList<T> HeapArray => m_HeapArray;
  22. public int Count { get; private set; }
  23. public T Min => m_HeapArray[0];
  24. public MinimumBinaryHeap(int minimumCapacity = 10)
  25. : this(Comparer<T>.Default, minimumCapacity) {}
  26. public MinimumBinaryHeap(IComparer<T> comparer, int minimumCapacity = 10)
  27. : this(null, comparer, minimumCapacity) {}
  28. internal MinimumBinaryHeap(ICollection<T> collection, IComparer<T> comparer, int minimumCapacity = 10)
  29. {
  30. if (minimumCapacity <= 0)
  31. {
  32. throw new ArgumentException("capacity must be more than 0");
  33. }
  34. m_MinimumCapacity = minimumCapacity;
  35. m_Comparer = comparer;
  36. lock (m_Lock)
  37. {
  38. Count = collection?.Count ?? 0;
  39. var startSize = Math.Max(Count, minimumCapacity);
  40. m_HeapArray = new T[startSize];
  41. if (collection is null)
  42. return;
  43. // Reset count since we insert all items.
  44. Count = 0;
  45. foreach (var item in collection)
  46. {
  47. Insert(item);
  48. }
  49. }
  50. }
  51. public void Insert(T item)
  52. {
  53. lock (m_Lock)
  54. {
  55. IncreaseHeapCapacityWhenFull();
  56. var itemIndex = Count;
  57. m_HeapArray[Count] = item;
  58. Count++;
  59. while (itemIndex != 0
  60. && m_Comparer.Compare(m_HeapArray[itemIndex], m_HeapArray[GetParentIndex(itemIndex)]) < 0)
  61. {
  62. Swap(ref m_HeapArray[itemIndex], ref m_HeapArray[GetParentIndex(itemIndex)]);
  63. itemIndex = GetParentIndex(itemIndex);
  64. }
  65. }
  66. }
  67. void IncreaseHeapCapacityWhenFull()
  68. {
  69. if (Count != m_HeapArray.Length)
  70. {
  71. return;
  72. }
  73. var newCapacity = (int)Math.Ceiling(Count * IncreaseFactor);
  74. var newHeapArray = new T[newCapacity];
  75. Array.Copy(m_HeapArray, newHeapArray, Count);
  76. m_HeapArray = newHeapArray;
  77. }
  78. public void Remove(T item)
  79. {
  80. lock (m_Lock)
  81. {
  82. var itemIndex = IndexOf(item);
  83. if (itemIndex < 0)
  84. return;
  85. while (itemIndex != 0)
  86. {
  87. Swap(ref m_HeapArray[itemIndex], ref m_HeapArray[GetParentIndex(itemIndex)]);
  88. itemIndex = GetParentIndex(itemIndex);
  89. }
  90. ExtractMin();
  91. }
  92. }
  93. int IndexOf(T item)
  94. {
  95. for (var i = 0; i < Count; i++)
  96. {
  97. if (m_HeapArray[i].Equals(item))
  98. {
  99. return i;
  100. }
  101. }
  102. return -1;
  103. }
  104. public T ExtractMin()
  105. {
  106. lock (m_Lock)
  107. {
  108. if (Count <= 0)
  109. {
  110. throw new InvalidOperationException("Can not ExtractMin: BinaryHeap is empty.");
  111. }
  112. var item = m_HeapArray[0];
  113. if (Count == 1)
  114. {
  115. Count--;
  116. m_HeapArray[0] = default;
  117. return item;
  118. }
  119. Count--;
  120. m_HeapArray[0] = m_HeapArray[Count];
  121. m_HeapArray[Count] = default;
  122. MinHeapify();
  123. DecreaseHeapCapacityWhenSpare();
  124. return item;
  125. }
  126. }
  127. void DecreaseHeapCapacityWhenSpare()
  128. {
  129. var spareThreshold = (int)Math.Ceiling(m_HeapArray.Length / DecreaseFactor);
  130. if (Count <= m_MinimumCapacity
  131. || Count > spareThreshold)
  132. {
  133. return;
  134. }
  135. var newHeapArray = new T[Count];
  136. Array.Copy(m_HeapArray, newHeapArray, Count);
  137. m_HeapArray = newHeapArray;
  138. }
  139. void MinHeapify()
  140. {
  141. int currentIndex;
  142. var smallest = 0;
  143. do
  144. {
  145. currentIndex = smallest;
  146. UpdateSmallestIndex();
  147. if (smallest == currentIndex)
  148. {
  149. return;
  150. }
  151. Swap(ref m_HeapArray[currentIndex], ref m_HeapArray[smallest]);
  152. }
  153. while (smallest != currentIndex);
  154. void UpdateSmallestIndex()
  155. {
  156. smallest = currentIndex;
  157. var leftChildIndex = GetLeftChildIndex(currentIndex);
  158. var rightChildIndex = GetRightChildIndex(currentIndex);
  159. UpdateSmallestIfCandidateIsSmaller(leftChildIndex);
  160. UpdateSmallestIfCandidateIsSmaller(rightChildIndex);
  161. }
  162. void UpdateSmallestIfCandidateIsSmaller(int candidate)
  163. {
  164. if (candidate >= Count
  165. || m_Comparer.Compare(m_HeapArray[candidate], m_HeapArray[smallest]) >= 0)
  166. {
  167. return;
  168. }
  169. smallest = candidate;
  170. }
  171. }
  172. static void Swap(ref T lhs, ref T rhs) => (lhs, rhs) = (rhs, lhs);
  173. static int GetParentIndex(int index) => (index - 1) / 2;
  174. static int GetLeftChildIndex(int index) => 2 * index + 1;
  175. static int GetRightChildIndex(int index) => 2 * index + 2;
  176. }
  177. }