FastPriorityQueue.cs 17 KB

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