PriorityQueue.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the Apache 2.0 License.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Collections.Generic;
  5. namespace System.Reactive
  6. {
  7. internal sealed class PriorityQueue<T> where T : IComparable<T>
  8. {
  9. private long _count = long.MinValue;
  10. private IndexedItem[] _items;
  11. private int _size;
  12. public PriorityQueue()
  13. : this(16)
  14. {
  15. }
  16. public PriorityQueue(int capacity)
  17. {
  18. _items = new IndexedItem[capacity];
  19. _size = 0;
  20. }
  21. private bool IsHigherPriority(int left, int right)
  22. {
  23. return _items[left].CompareTo(_items[right]) < 0;
  24. }
  25. private int Percolate(int index)
  26. {
  27. if (index >= _size || index < 0)
  28. {
  29. return index;
  30. }
  31. var parent = (index - 1) / 2;
  32. if (parent < 0 || parent == index)
  33. {
  34. return index;
  35. }
  36. if (IsHigherPriority(index, parent))
  37. {
  38. var temp = _items[index];
  39. _items[index] = _items[parent];
  40. _items[parent] = temp;
  41. return Percolate(parent);
  42. }
  43. return index;
  44. }
  45. private void Heapify(int index)
  46. {
  47. if (index >= _size || index < 0)
  48. {
  49. return;
  50. }
  51. var left = 2 * index + 1;
  52. var right = 2 * index + 2;
  53. var first = index;
  54. if (left < _size && IsHigherPriority(left, first))
  55. {
  56. first = left;
  57. }
  58. if (right < _size && IsHigherPriority(right, first))
  59. {
  60. first = right;
  61. }
  62. if (first != index)
  63. {
  64. var temp = _items[index];
  65. _items[index] = _items[first];
  66. _items[first] = temp;
  67. Heapify(first);
  68. }
  69. }
  70. public int Count => _size;
  71. public T Peek()
  72. {
  73. if (_size == 0)
  74. {
  75. throw new InvalidOperationException(Strings_Core.HEAP_EMPTY);
  76. }
  77. return _items[0].Value;
  78. }
  79. private void RemoveAt(int index)
  80. {
  81. _items[index] = _items[--_size];
  82. _items[_size] = default;
  83. if (Percolate(index) == index)
  84. {
  85. Heapify(index);
  86. }
  87. if (_size < _items.Length / 4)
  88. {
  89. var temp = _items;
  90. _items = new IndexedItem[_items.Length / 2];
  91. Array.Copy(temp, 0, _items, 0, _size);
  92. }
  93. }
  94. public T Dequeue()
  95. {
  96. var result = Peek();
  97. RemoveAt(0);
  98. return result;
  99. }
  100. public void Enqueue(T item)
  101. {
  102. if (_size >= _items.Length)
  103. {
  104. var temp = _items;
  105. _items = new IndexedItem[_items.Length * 2];
  106. Array.Copy(temp, _items, temp.Length);
  107. }
  108. var index = _size++;
  109. _items[index] = new IndexedItem { Value = item, Id = ++_count };
  110. Percolate(index);
  111. }
  112. public bool Remove(T item)
  113. {
  114. for (var i = 0; i < _size; ++i)
  115. {
  116. if (EqualityComparer<T>.Default.Equals(_items[i].Value, item))
  117. {
  118. RemoveAt(i);
  119. return true;
  120. }
  121. }
  122. return false;
  123. }
  124. private struct IndexedItem : IComparable<IndexedItem>
  125. {
  126. public T Value;
  127. public long Id;
  128. public int CompareTo(IndexedItem other)
  129. {
  130. var c = Value.CompareTo(other.Value);
  131. if (c == 0)
  132. {
  133. c = Id.CompareTo(other.Id);
  134. }
  135. return c;
  136. }
  137. }
  138. }
  139. }