MinHeap.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. using System;
  2. using System.Threading;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.Runtime.InteropServices;
  6. namespace OpenSim.Framework
  7. {
  8. public interface IHandle { }
  9. [Serializable, ComVisible(false)]
  10. public class MinHeap<T> : ICollection<T>, ICollection
  11. {
  12. private class Handle : IHandle
  13. {
  14. internal int index = -1;
  15. internal MinHeap<T> heap = null;
  16. internal void Clear()
  17. {
  18. this.index = -1;
  19. this.heap = null;
  20. }
  21. }
  22. private struct HeapItem
  23. {
  24. internal T value;
  25. internal Handle handle;
  26. internal HeapItem(T value, Handle handle)
  27. {
  28. this.value = value;
  29. this.handle = handle;
  30. }
  31. internal void Clear()
  32. {
  33. this.value = default(T);
  34. if (this.handle != null)
  35. {
  36. this.handle.Clear();
  37. this.handle = null;
  38. }
  39. }
  40. }
  41. public const int DEFAULT_CAPACITY = 4;
  42. private HeapItem[] items;
  43. private int size;
  44. private object sync_root;
  45. private int version;
  46. private Comparison<T> comparison;
  47. public MinHeap() : this(DEFAULT_CAPACITY, Comparer<T>.Default) { }
  48. public MinHeap(int capacity) : this(capacity, Comparer<T>.Default) { }
  49. public MinHeap(IComparer<T> comparer) : this(DEFAULT_CAPACITY, comparer) { }
  50. public MinHeap(int capacity, IComparer<T> comparer) :
  51. this(capacity, new Comparison<T>(comparer.Compare)) { }
  52. public MinHeap(Comparison<T> comparison) : this(DEFAULT_CAPACITY, comparison) { }
  53. public MinHeap(int capacity, Comparison<T> comparison)
  54. {
  55. this.items = new HeapItem[capacity];
  56. this.comparison = comparison;
  57. this.size = this.version = 0;
  58. }
  59. public int Count { get { return this.size; } }
  60. public bool IsReadOnly { get { return false; } }
  61. public bool IsSynchronized { get { return false; } }
  62. public T this[IHandle key]
  63. {
  64. get
  65. {
  66. Handle handle = ValidateThisHandle(key);
  67. return this.items[handle.index].value;
  68. }
  69. set
  70. {
  71. Handle handle = ValidateThisHandle(key);
  72. this.items[handle.index].value = value;
  73. if (!BubbleUp(handle.index))
  74. BubbleDown(handle.index);
  75. }
  76. }
  77. public object SyncRoot
  78. {
  79. get
  80. {
  81. if (this.sync_root == null)
  82. Interlocked.CompareExchange<object>(ref this.sync_root, new object(), null);
  83. return this.sync_root;
  84. }
  85. }
  86. private Handle ValidateHandle(IHandle ihandle)
  87. {
  88. if (ihandle == null)
  89. throw new ArgumentNullException("handle");
  90. Handle handle = ihandle as Handle;
  91. if (handle == null)
  92. throw new InvalidOperationException("handle is not valid");
  93. return handle;
  94. }
  95. private Handle ValidateThisHandle(IHandle ihandle)
  96. {
  97. Handle handle = ValidateHandle(ihandle);
  98. if (!object.ReferenceEquals(handle.heap, this))
  99. throw new InvalidOperationException("handle is not valid for this heap");
  100. if (handle.index < 0)
  101. throw new InvalidOperationException("handle is not associated to a value");
  102. return handle;
  103. }
  104. private void Set(HeapItem item, int index)
  105. {
  106. this.items[index] = item;
  107. if (item.handle != null)
  108. item.handle.index = index;
  109. }
  110. private bool BubbleUp(int index)
  111. {
  112. HeapItem item = this.items[index];
  113. int current, parent;
  114. for (current = index, parent = (current - 1) / 2;
  115. (current > 0) && (this.comparison(this.items[parent].value, item.value)) > 0;
  116. current = parent, parent = (current - 1) / 2)
  117. {
  118. Set(this.items[parent], current);
  119. }
  120. if (current != index)
  121. {
  122. Set(item, current);
  123. ++this.version;
  124. return true;
  125. }
  126. return false;
  127. }
  128. private void BubbleDown(int index)
  129. {
  130. HeapItem item = this.items[index];
  131. int current, child;
  132. for (current = index, child = (2 * current) + 1;
  133. current < this.size / 2;
  134. current = child, child = (2 * current) + 1)
  135. {
  136. if ((child < this.size - 1) && this.comparison(this.items[child].value, this.items[child + 1].value) > 0)
  137. ++child;
  138. if (this.comparison(this.items[child].value, item.value) >= 0)
  139. break;
  140. Set(this.items[child], current);
  141. }
  142. if (current != index)
  143. {
  144. Set(item, current);
  145. ++this.version;
  146. }
  147. }
  148. public bool TryGetValue(IHandle key, out T value)
  149. {
  150. Handle handle = ValidateHandle(key);
  151. if (handle.index > -1)
  152. {
  153. value = this.items[handle.index].value;
  154. return true;
  155. }
  156. value = default(T);
  157. return false;
  158. }
  159. public bool ContainsHandle(IHandle ihandle)
  160. {
  161. Handle handle = ValidateHandle(ihandle);
  162. return object.ReferenceEquals(handle.heap, this) && handle.index > -1;
  163. }
  164. public void Add(T value, ref IHandle handle)
  165. {
  166. if (handle == null)
  167. handle = new Handle();
  168. Add(value, handle);
  169. }
  170. public void Add(T value, IHandle ihandle)
  171. {
  172. if (this.size == this.items.Length)
  173. {
  174. int capacity = (int)((this.items.Length * 200L) / 100L);
  175. if (capacity < (this.items.Length + DEFAULT_CAPACITY))
  176. capacity = this.items.Length + DEFAULT_CAPACITY;
  177. Array.Resize<HeapItem>(ref this.items, capacity);
  178. }
  179. Handle handle = null;
  180. if (ihandle != null)
  181. {
  182. handle = ValidateHandle(ihandle);
  183. handle.heap = this;
  184. }
  185. HeapItem item = new MinHeap<T>.HeapItem(value, handle);
  186. Set(item, this.size);
  187. BubbleUp(this.size++);
  188. }
  189. public void Add(T value)
  190. {
  191. Add(value, null);
  192. }
  193. public T Min()
  194. {
  195. if (this.size == 0)
  196. throw new InvalidOperationException("Heap is empty");
  197. return this.items[0].value;
  198. }
  199. public void Clear()
  200. {
  201. for (int index = 0; index < this.size; ++index)
  202. this.items[index].Clear();
  203. this.size = 0;
  204. ++this.version;
  205. }
  206. public void TrimExcess()
  207. {
  208. int length = (int)(this.items.Length * 0.9);
  209. if (this.size < length)
  210. Array.Resize<HeapItem>(ref this.items, Math.Min(this.size, DEFAULT_CAPACITY));
  211. }
  212. private void RemoveAt(int index)
  213. {
  214. if (this.size == 0)
  215. throw new InvalidOperationException("Heap is empty");
  216. if (index >= this.size)
  217. throw new ArgumentOutOfRangeException("index");
  218. this.items[index].Clear();
  219. if (--this.size > 0 && index != this.size)
  220. {
  221. Set(this.items[this.size], index);
  222. if (!BubbleUp(index))
  223. BubbleDown(index);
  224. }
  225. }
  226. public T RemoveMin()
  227. {
  228. if (this.size == 0)
  229. throw new InvalidOperationException("Heap is empty");
  230. HeapItem item = this.items[0];
  231. RemoveAt(0);
  232. return item.value;
  233. }
  234. public T Remove(IHandle ihandle)
  235. {
  236. Handle handle = ValidateThisHandle(ihandle);
  237. HeapItem item = this.items[handle.index];
  238. RemoveAt(handle.index);
  239. return item.value;
  240. }
  241. private int GetIndex(T value)
  242. {
  243. EqualityComparer<T> comparer = EqualityComparer<T>.Default;
  244. int index;
  245. for (index = 0; index < this.size; ++index)
  246. {
  247. if (comparer.Equals(this.items[index].value, value))
  248. return index;
  249. }
  250. return -1;
  251. }
  252. public bool Contains(T value)
  253. {
  254. return GetIndex(value) != -1;
  255. }
  256. public bool Remove(T value)
  257. {
  258. int index = GetIndex(value);
  259. if (index != -1)
  260. {
  261. RemoveAt(index);
  262. return true;
  263. }
  264. return false;
  265. }
  266. public void CopyTo(T[] array, int index)
  267. {
  268. if (array == null)
  269. throw new ArgumentNullException("array");
  270. if (array.Rank != 1)
  271. throw new ArgumentException("Multidimensional array not supported");
  272. if (array.GetLowerBound(0) != 0)
  273. throw new ArgumentException("Non-zero lower bound array not supported");
  274. int length = array.Length;
  275. if ((index < 0) || (index > length))
  276. throw new ArgumentOutOfRangeException("index");
  277. if ((length - index) < this.size)
  278. throw new ArgumentException("Not enough space available in array starting at index");
  279. for (int i = 0; i < this.size; ++i)
  280. array[index + i] = this.items[i].value;
  281. }
  282. public void CopyTo(Array array, int index)
  283. {
  284. if (array == null)
  285. throw new ArgumentNullException("array");
  286. if (array.Rank != 1)
  287. throw new ArgumentException("Multidimensional array not supported");
  288. if (array.GetLowerBound(0) != 0)
  289. throw new ArgumentException("Non-zero lower bound array not supported");
  290. int length = array.Length;
  291. if ((index < 0) || (index > length))
  292. throw new ArgumentOutOfRangeException("index");
  293. if ((length - index) < this.size)
  294. throw new ArgumentException("Not enough space available in array starting at index");
  295. try
  296. {
  297. for (int i = 0; i < this.size; ++i)
  298. array.SetValue(this.items[i].value, index + i);
  299. }
  300. catch (ArrayTypeMismatchException)
  301. {
  302. throw new ArgumentException("Invalid array type");
  303. }
  304. }
  305. public IEnumerator<T> GetEnumerator()
  306. {
  307. int version = this.version;
  308. for (int index = 0; index < this.size; ++index)
  309. {
  310. if (version != this.version)
  311. throw new InvalidOperationException("Heap was modified while enumerating");
  312. yield return this.items[index].value;
  313. }
  314. }
  315. IEnumerator IEnumerable.GetEnumerator()
  316. {
  317. return GetEnumerator();
  318. }
  319. }
  320. }