GenericPriorityQueue.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. namespace IFramework.Queue
  5. {
  6. /// <summary>
  7. /// 泛型优先级队列
  8. /// </summary>
  9. /// <typeparam name="TItem"></typeparam>
  10. /// <typeparam name="TPriority"></typeparam>
  11. public sealed class GenericPriorityQueue<TItem, TPriority> : IFixedSizePriorityQueue<TItem, TPriority> where TItem : GenericPriorityQueueNode<TPriority> where TPriority : IComparable<TPriority>
  12. {
  13. private int _numNodes;
  14. private TItem[] _nodes;
  15. private long _numNodesEverEnqueued;
  16. private readonly Comparison<TPriority> _comparer;
  17. /// <summary>
  18. /// Ctor
  19. /// </summary>
  20. /// <param name="maxNodes">允许入队的最大数量(如果超过将导致未定义的操作)</param>
  21. public GenericPriorityQueue(int maxNodes) : this(maxNodes, Comparer<TPriority>.Default) { }
  22. /// <summary>
  23. /// Ctor
  24. /// </summary>
  25. /// <param name="maxNodes">允许入队的最大数量(如果超过将导致未定义的操作)</param>
  26. /// <param name="comparer">用于比较优先级的TPriority值</param>
  27. public GenericPriorityQueue(int maxNodes, IComparer<TPriority> comparer) : this(maxNodes, comparer.Compare) { }
  28. /// <summary>
  29. /// Ctor
  30. /// </summary>
  31. /// <param name="maxNodes">允许入队的最大数量(如果超过将导致未定义的操作)</param>
  32. /// <param name="comparer">用于比较优先级的TPriority值</param>
  33. public GenericPriorityQueue(int maxNodes, Comparison<TPriority> comparer)
  34. {
  35. #if DEBUG
  36. if (maxNodes <= 0)
  37. {
  38. throw new InvalidOperationException("New queue size cannot be smaller than 1");
  39. }
  40. #endif
  41. _numNodes = 0;
  42. _nodes = new TItem[maxNodes + 1];
  43. _numNodesEverEnqueued = 0;
  44. _comparer = comparer;
  45. }
  46. /// <summary>
  47. /// 返回队列里的元素数量<br />
  48. /// O(1)
  49. /// </summary>
  50. public int count
  51. {
  52. get
  53. {
  54. return _numNodes;
  55. }
  56. }
  57. /// <summary>
  58. /// 队列中可以入队的最大数量<br />
  59. /// 如果入队数量超过队列的大小(Count == MaxSize时Enqueue()),会导致未定义的操作<br />
  60. /// O(1)
  61. /// </summary>
  62. public int capcity
  63. {
  64. get
  65. {
  66. return _nodes.Length - 1;
  67. }
  68. }
  69. /// <summary>
  70. /// 移除队列里的所有元素<br />
  71. /// O(n) (因此请勿频繁使用此方法)
  72. /// </summary>
  73. #if NET_VERSION_4_5
  74. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  75. #endif
  76. public void Clear()
  77. {
  78. Array.Clear(_nodes, 1, _numNodes);
  79. _numNodes = 0;
  80. }
  81. /// <summary>
  82. /// 判断当前元素是否在队列中<br />
  83. /// 如果元素被添加到其他的队列,则结果是不确定的,
  84. /// 除非调用了之前队列的ResetNode(node)方法<br />
  85. /// O(1)
  86. /// </summary>
  87. /// <param name="node">需要判断的元素</param>
  88. /// <returns>如果队列包含这个元素则返回true 否则为false</returns>
  89. #if NET_VERSION_4_5
  90. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  91. #endif
  92. public bool Contains(TItem node)
  93. {
  94. #if DEBUG
  95. if (node == null)
  96. {
  97. throw new ArgumentNullException("node");
  98. }
  99. if (node.position < 0 || node.position >= _nodes.Length)
  100. {
  101. throw new InvalidOperationException("node.position has been corrupted. Did you change it manually?");
  102. }
  103. #endif
  104. return (_nodes[node.position] == node);
  105. }
  106. /// <summary>
  107. /// 将优先级节点入队,优先级值小的将会排在队列前面,优先级相同的节点以先进先出排序<br />
  108. /// 如果队列是满的,则执行未定义的操作<br />
  109. /// 如果节点元素已经入队了,则执行未定义的操作<br />
  110. /// 如果节点已经在队列中了,除非在此之前调用了之前队列的ResetNode(node)方法,否则结果是未定义的<br />
  111. /// O(log n)
  112. /// </summary>
  113. #if NET_VERSION_4_5
  114. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  115. #endif
  116. public void Enqueue(TItem node, TPriority priority)
  117. {
  118. #if DEBUG
  119. if (node == null)
  120. {
  121. throw new ArgumentNullException("node");
  122. }
  123. if (_numNodes >= _nodes.Length - 1)
  124. {
  125. throw new InvalidOperationException($"Queue is full - node cannot be added: {node}");
  126. }
  127. if (Contains(node))
  128. {
  129. throw new InvalidOperationException($"Node is already enqueued: {node}");
  130. }
  131. #endif
  132. node.priority = priority;
  133. _numNodes++;
  134. _nodes[_numNodes] = node;
  135. node.position = _numNodes;
  136. node.insertPosition = _numNodesEverEnqueued++;
  137. CascadeUp(node);
  138. }
  139. #if NET_VERSION_4_5
  140. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  141. #endif
  142. private void CascadeUp(TItem node)
  143. {
  144. int parent;
  145. if (node.position > 1)
  146. {
  147. parent = node.position >> 1;
  148. TItem parentNode = _nodes[parent];
  149. if (HasHigherPriority(parentNode, node))
  150. return;
  151. _nodes[node.position] = parentNode;
  152. parentNode.position = node.position;
  153. node.position = parent;
  154. }
  155. else
  156. {
  157. return;
  158. }
  159. while (parent > 1)
  160. {
  161. parent >>= 1;
  162. TItem parentNode = _nodes[parent];
  163. if (HasHigherPriority(parentNode, node))
  164. break;
  165. _nodes[node.position] = parentNode;
  166. parentNode.position = node.position;
  167. node.position = parent;
  168. }
  169. _nodes[node.position] = node;
  170. }
  171. #if NET_VERSION_4_5
  172. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  173. #endif
  174. private void CascadeDown(TItem node)
  175. {
  176. int finalQueueIndex = node.position;
  177. int childLeftIndex = 2 * finalQueueIndex;
  178. if (childLeftIndex > _numNodes)
  179. {
  180. return;
  181. }
  182. int childRightIndex = childLeftIndex + 1;
  183. TItem childLeft = _nodes[childLeftIndex];
  184. if (HasHigherPriority(childLeft, node))
  185. {
  186. if (childRightIndex > _numNodes)
  187. {
  188. node.position = childLeftIndex;
  189. childLeft.position = finalQueueIndex;
  190. _nodes[finalQueueIndex] = childLeft;
  191. _nodes[childLeftIndex] = node;
  192. return;
  193. }
  194. TItem childRight = _nodes[childRightIndex];
  195. if (HasHigherPriority(childLeft, childRight))
  196. {
  197. childLeft.position = finalQueueIndex;
  198. _nodes[finalQueueIndex] = childLeft;
  199. finalQueueIndex = childLeftIndex;
  200. }
  201. else
  202. {
  203. childRight.position = finalQueueIndex;
  204. _nodes[finalQueueIndex] = childRight;
  205. finalQueueIndex = childRightIndex;
  206. }
  207. }
  208. else if (childRightIndex > _numNodes)
  209. {
  210. return;
  211. }
  212. else
  213. {
  214. TItem childRight = _nodes[childRightIndex];
  215. if (HasHigherPriority(childRight, node))
  216. {
  217. childRight.position = finalQueueIndex;
  218. _nodes[finalQueueIndex] = childRight;
  219. finalQueueIndex = childRightIndex;
  220. }
  221. else
  222. {
  223. return;
  224. }
  225. }
  226. while (true)
  227. {
  228. childLeftIndex = 2 * finalQueueIndex;
  229. if (childLeftIndex > _numNodes)
  230. {
  231. node.position = finalQueueIndex;
  232. _nodes[finalQueueIndex] = node;
  233. break;
  234. }
  235. childRightIndex = childLeftIndex + 1;
  236. childLeft = _nodes[childLeftIndex];
  237. if (HasHigherPriority(childLeft, node))
  238. {
  239. if (childRightIndex > _numNodes)
  240. {
  241. node.position = childLeftIndex;
  242. childLeft.position = finalQueueIndex;
  243. _nodes[finalQueueIndex] = childLeft;
  244. _nodes[childLeftIndex] = node;
  245. break;
  246. }
  247. TItem childRight = _nodes[childRightIndex];
  248. if (HasHigherPriority(childLeft, childRight))
  249. {
  250. childLeft.position = finalQueueIndex;
  251. _nodes[finalQueueIndex] = childLeft;
  252. finalQueueIndex = childLeftIndex;
  253. }
  254. else
  255. {
  256. childRight.position = finalQueueIndex;
  257. _nodes[finalQueueIndex] = childRight;
  258. finalQueueIndex = childRightIndex;
  259. }
  260. }
  261. else if (childRightIndex > _numNodes)
  262. {
  263. node.position = finalQueueIndex;
  264. _nodes[finalQueueIndex] = node;
  265. break;
  266. }
  267. else
  268. {
  269. TItem childRight = _nodes[childRightIndex];
  270. if (HasHigherPriority(childRight, node))
  271. {
  272. childRight.position = finalQueueIndex;
  273. _nodes[finalQueueIndex] = childRight;
  274. finalQueueIndex = childRightIndex;
  275. }
  276. else
  277. {
  278. node.position = finalQueueIndex;
  279. _nodes[finalQueueIndex] = node;
  280. break;
  281. }
  282. }
  283. }
  284. }
  285. /// <summary>
  286. /// 对两个参数的优先级进行比较
  287. /// </summary>
  288. /// <param name="higher">第一个参数</param>
  289. /// <param name="lower">第二个参数</param>
  290. /// <returns>
  291. /// 如果第一个参数的优先级大于第二个参数则返回true,否则返回false<br />
  292. /// 如果两个参数为同一个节点,返回false
  293. /// </returns>
  294. #if NET_VERSION_4_5
  295. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  296. #endif
  297. private bool HasHigherPriority(TItem higher, TItem lower)
  298. {
  299. var cmp = _comparer(higher.priority, lower.priority);
  300. return (cmp < 0 || (cmp == 0 && higher.insertPosition < lower.insertPosition));
  301. }
  302. /// <summary>
  303. /// 队列头部出队
  304. /// 如果队列为空则执行未定义的操作<br />
  305. /// O(log n)
  306. /// </summary>
  307. /// <returns>出队的元素</returns>
  308. #if NET_VERSION_4_5
  309. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  310. #endif
  311. public TItem Dequeue()
  312. {
  313. #if DEBUG
  314. if (_numNodes <= 0)
  315. {
  316. throw new InvalidOperationException("Cannot call Dequeue() on an empty queue");
  317. }
  318. #endif
  319. TItem returnMe = _nodes[1];
  320. //如果节点元素已经是最后一个节点,则直接移除
  321. if (_numNodes == 1)
  322. {
  323. _nodes[1] = null;
  324. _numNodes = 0;
  325. return returnMe;
  326. }
  327. //将节点与最后一个节点对换
  328. TItem formerLastNode = _nodes[_numNodes];
  329. _nodes[1] = formerLastNode;
  330. formerLastNode.position = 1;
  331. _nodes[_numNodes] = null;
  332. _numNodes--;
  333. //将formerLastNode (不再是最后一个节点)向下冒泡
  334. CascadeDown(formerLastNode);
  335. return returnMe;
  336. }
  337. /// <summary>
  338. /// 重新设置队列的大小,使其可以容纳更多的节点,当前的所有节点都会保留<br />
  339. /// 如果试图将队列大小设置成比当前队列中的数量小时,会执行未定义的操作<br />
  340. /// O(n)
  341. /// </summary>
  342. public void Resize(int maxNodes)
  343. {
  344. #if DEBUG
  345. if (maxNodes <= 0)
  346. {
  347. throw new InvalidOperationException("Queue size cannot be smaller than 1");
  348. }
  349. if (maxNodes < _numNodes)
  350. {
  351. throw new InvalidOperationException($"Called Resize({ maxNodes }), but current queue contains { _numNodes } nodes");
  352. }
  353. #endif
  354. TItem[] newArray = new TItem[maxNodes + 1];
  355. int highestIndexToCopy = Math.Min(maxNodes, _numNodes);
  356. Array.Copy(_nodes, newArray, highestIndexToCopy + 1);
  357. _nodes = newArray;
  358. }
  359. /// <summary>
  360. /// 队列的第一个元素<br />
  361. /// 如果队列为空,则执行未定义的操作<br />
  362. /// O(1)
  363. /// </summary>
  364. public TItem first
  365. {
  366. get
  367. {
  368. #if DEBUG
  369. if (_numNodes <= 0)
  370. {
  371. throw new InvalidOperationException("Cannot call .first on an empty queue");
  372. }
  373. #endif
  374. return _nodes[1];
  375. }
  376. }
  377. /// <summary>
  378. /// 更改队列里某个节点的优先级<br />
  379. /// <b>忘记调用这个方法会导致队列损坏!</b><br />
  380. /// 对不在这个队列中的节点元素调用这个方法会执行未定义的行为<br />
  381. /// O(log n)
  382. /// </summary>
  383. #if NET_VERSION_4_5
  384. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  385. #endif
  386. public void UpdatePriority(TItem node, TPriority priority)
  387. {
  388. #if DEBUG
  389. if (node == null)
  390. {
  391. throw new ArgumentNullException("node");
  392. }
  393. if (!Contains(node))
  394. {
  395. throw new InvalidOperationException($"Cannot call UpdatePriority() on a node which is not enqueued: {node}");
  396. }
  397. #endif
  398. node.priority = priority;
  399. OnNodeUpdated(node);
  400. }
  401. #if NET_VERSION_4_5
  402. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  403. #endif
  404. private void OnNodeUpdated(TItem node)
  405. {
  406. //按需向上或向下冒泡更新节点
  407. int parentIndex = node.position >> 1;
  408. if (parentIndex > 0 && HasHigherPriority(node, _nodes[parentIndex]))
  409. {
  410. CascadeUp(node);
  411. }
  412. else
  413. {
  414. //如果 parentNode == node(node是根节点) 则会调用CascadeDown
  415. CascadeDown(node);
  416. }
  417. }
  418. /// <summary>
  419. /// 从队列中删除给定节点元素,这个节点不一定是队列的头<br />
  420. /// 如果节点并未在队列中,结果是未定义的,如果不确定,则先使用Contains()确认<br />
  421. /// O(log n)
  422. /// </summary>
  423. #if NET_VERSION_4_5
  424. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  425. #endif
  426. public void Remove(TItem node)
  427. {
  428. #if DEBUG
  429. if (node == null)
  430. {
  431. throw new ArgumentNullException("node");
  432. }
  433. if (!Contains(node))
  434. {
  435. throw new InvalidOperationException($"Cannot call Remove() on a node which is not enqueued: {node}");
  436. }
  437. #endif
  438. //如果节点元素已经是最后一个节点,则直接移除
  439. if (node.position == _numNodes)
  440. {
  441. _nodes[_numNodes] = null;
  442. _numNodes--;
  443. return;
  444. }
  445. //将节点与最后一个节点对换
  446. TItem formerLastNode = _nodes[_numNodes];
  447. _nodes[node.position] = formerLastNode;
  448. formerLastNode.position = node.position;
  449. _nodes[_numNodes] = null;
  450. _numNodes--;
  451. //将formerLastNode (不再是最后一个节点)按需向上或者向下冒泡排序
  452. OnNodeUpdated(formerLastNode);
  453. }
  454. /// <summary>
  455. /// 默认情况下有加入过一个队列的节点元素不能添加到另一个队列<br />
  456. /// 如果需要这么做,则在添加到另一个队列前调用当前队列的此方法<br />
  457. /// 如果节点当前在节点中或者属于其他队列,则结果是未定义的
  458. /// </summary>
  459. #if NET_VERSION_4_5
  460. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  461. #endif
  462. public void ResetNode(TItem node)
  463. {
  464. #if DEBUG
  465. if (node == null)
  466. {
  467. throw new ArgumentNullException("node");
  468. }
  469. if (Contains(node))
  470. {
  471. throw new InvalidOperationException("node.ResetNode was called on a node that is still in the queue");
  472. }
  473. #endif
  474. node.position = 0;
  475. }
  476. /// <summary>
  477. /// 迭代器
  478. /// </summary>
  479. /// <returns>迭代器</returns>
  480. public IEnumerator<TItem> GetEnumerator()
  481. {
  482. #if NET_VERSION_4_5 // ArraySegment在4.5之前没有 实现IEnumerable接口
  483. IEnumerable<TItem> e = new ArraySegment<TItem>(_nodes, 1, _numNodes);
  484. return e.GetEnumerator();
  485. #else
  486. for (int i = 1; i <= _numNodes; i++)
  487. yield return _nodes[i];
  488. #endif
  489. }
  490. IEnumerator IEnumerable.GetEnumerator()
  491. {
  492. return GetEnumerator();
  493. }
  494. }
  495. }