PriorityQueue.cs 4.0 KB

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