PriorityQueue.cs 4.0 KB

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