fibonacci-heap.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. /**
  2. * Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Gianluca Tomasello <giagitom@gmail.com>
  5. *
  6. * Adapted from https://github.com/gwtw/ts-fibonacci-heap, Copyright (c) 2014 Daniel Imms, MIT
  7. */
  8. interface INode<K, V> {
  9. key: K;
  10. value?: V;
  11. }
  12. type CompareFunction<K, V> = (a: INode<K, V>, b: INode<K, V>) => number;
  13. class Node<K, V> implements INode<K, V> {
  14. public key: K;
  15. public value: V | undefined;
  16. public prev: Node<K, V>;
  17. public next: Node<K, V>;
  18. public parent: Node<K, V> | null = null;
  19. public child: Node<K, V> | null = null;
  20. public degree: number = 0;
  21. public isMarked: boolean = false;
  22. constructor(key: K, value?: V) {
  23. this.key = key;
  24. this.value = value;
  25. this.prev = this;
  26. this.next = this;
  27. }
  28. }
  29. class NodeListIterator<K, V> {
  30. private _index: number;
  31. private _items: Node<K, V>[];
  32. private _len: number;
  33. /**
  34. * Creates an Iterator used to simplify the consolidate() method. It works by
  35. * making a shallow copy of the nodes in the root list and iterating over the
  36. * shallow copy instead of the source as the source will be modified.
  37. * @param start A node from the root list.
  38. */
  39. constructor(start?: Node<K, V>) {
  40. this._index = -1;
  41. this._items = [];
  42. this._len = 0;
  43. if (start) {
  44. let current = start, l = 0;
  45. do {
  46. this._items[l++] = current;
  47. current = current.next;
  48. } while (start !== current);
  49. this._len = l;
  50. }
  51. }
  52. /**
  53. * @return Whether there is a next node in the iterator.
  54. */
  55. public hasNext(): boolean {
  56. return this._index < this._len - 1;
  57. }
  58. /**
  59. * @return The next node.
  60. */
  61. public next(): Node<K, V> {
  62. return this._items[++this._index];
  63. }
  64. /**
  65. * @return Resets iterator to reuse it.
  66. */
  67. public reset(start: Node<K, V>) {
  68. this._index = -1;
  69. this._len = 0;
  70. let current = start, l = 0;
  71. do {
  72. this._items[l++] = current;
  73. current = current.next;
  74. } while (start !== current);
  75. this._len = l;
  76. }
  77. }
  78. const tmpIt = new NodeListIterator<any, any>();
  79. /**
  80. * A Fibonacci heap data structure with a key and optional value.
  81. */
  82. export class FibonacciHeap<K, V> {
  83. private _minNode: Node<K, V> | null = null;
  84. private _nodeCount: number = 0;
  85. private _compare: CompareFunction<K, V>;
  86. constructor(
  87. compare?: CompareFunction<K, V>
  88. ) {
  89. this._compare = compare ? compare : this._defaultCompare;
  90. }
  91. /**
  92. * Clears the heap's data, making it an empty heap.
  93. */
  94. public clear(): void {
  95. this._minNode = null;
  96. this._nodeCount = 0;
  97. }
  98. /**
  99. * Decreases a key of a node.
  100. * @param node The node to decrease the key of.
  101. * @param newKey The new key to assign to the node.
  102. */
  103. public decreaseKey(node: Node<K, V>, newKey: K): void {
  104. if (!node) {
  105. throw new Error('Cannot decrease key of non-existent node');
  106. }
  107. if (this._compare({ key: newKey }, { key: node.key }) > 0) {
  108. throw new Error('New key is larger than old key');
  109. }
  110. node.key = newKey;
  111. const parent = node.parent;
  112. if (parent && this._compare(node, parent) < 0) {
  113. this._cut(node, parent, <Node<K, V>> this._minNode);
  114. this._cascadingCut(parent, <Node<K, V>> this._minNode);
  115. }
  116. if (this._compare(node, <Node<K, V>> this._minNode) < 0) {
  117. this._minNode = node;
  118. }
  119. }
  120. /**
  121. * Deletes a node.
  122. * @param node The node to delete.
  123. */
  124. public delete(node: Node<K, V>): void {
  125. // This is a special implementation of decreaseKey that sets the argument to
  126. // the minimum value. This is necessary to make generic keys work, since there
  127. // is no MIN_VALUE constant for generic types.
  128. const parent = node.parent;
  129. if (parent) {
  130. this._cut(node, parent, <Node<K, V>> this._minNode);
  131. this._cascadingCut(parent, <Node<K, V>> this._minNode);
  132. }
  133. this._minNode = node;
  134. this.extractMinimum();
  135. }
  136. /**
  137. * Extracts and returns the minimum node from the heap.
  138. * @return The heap's minimum node or null if the heap is empty.
  139. */
  140. public extractMinimum(): Node<K, V> | null {
  141. const extractedMin = this._minNode;
  142. if (extractedMin) {
  143. // Set parent to null for the minimum's children
  144. if (extractedMin.child) {
  145. let child = extractedMin.child;
  146. do {
  147. child.parent = null;
  148. child = child.next;
  149. } while (child !== extractedMin.child);
  150. }
  151. let nextInRootList = null;
  152. if (extractedMin.next !== extractedMin) {
  153. nextInRootList = extractedMin.next;
  154. }
  155. // Remove min from root list
  156. this._removeNodeFromList(extractedMin);
  157. this._nodeCount--;
  158. // Merge the children of the minimum node with the root list
  159. this._minNode = this._mergeLists(nextInRootList, extractedMin.child);
  160. if (this._minNode) {
  161. this._minNode = this._consolidate(this._minNode);
  162. }
  163. }
  164. return extractedMin;
  165. }
  166. /**
  167. * Returns the minimum node from the heap.
  168. * @return The heap's minimum node or null if the heap is empty.
  169. */
  170. public findMinimum(): Node<K, V> | null {
  171. return this._minNode;
  172. }
  173. /**
  174. * Inserts a new key-value pair into the heap.
  175. * @param key The key to insert.
  176. * @param value The value to insert.
  177. * @return node The inserted node.
  178. */
  179. public insert(key: K, value?: V): Node<K, V> {
  180. const node = new Node(key, value);
  181. this._minNode = this._mergeLists(this._minNode, node);
  182. this._nodeCount++;
  183. return node;
  184. }
  185. /**
  186. * @return Whether the heap is empty.
  187. */
  188. public isEmpty(): boolean {
  189. return this._minNode === null;
  190. }
  191. /**
  192. * @return The size of the heap.
  193. */
  194. public size(): number {
  195. if (this._minNode === null) {
  196. return 0;
  197. }
  198. return this._getNodeListSize(this._minNode);
  199. }
  200. /**
  201. * Joins another heap to this heap.
  202. * @param other The other heap.
  203. */
  204. public union(other: FibonacciHeap<K, V>): void {
  205. this._minNode = this._mergeLists(this._minNode, other._minNode);
  206. this._nodeCount += other._nodeCount;
  207. }
  208. /**
  209. * Compares two nodes with each other.
  210. * @param a The first key to compare.
  211. * @param b The second key to compare.
  212. * @return -1, 0 or 1 if a < b, a == b or a > b respectively.
  213. */
  214. private _defaultCompare(a: INode<K, V>, b: INode<K, V>): number {
  215. if (a.key > b.key) {
  216. return 1;
  217. }
  218. if (a.key < b.key) {
  219. return -1;
  220. }
  221. return 0;
  222. }
  223. /**
  224. * Cut the link between a node and its parent, moving the node to the root list.
  225. * @param node The node being cut.
  226. * @param parent The parent of the node being cut.
  227. * @param minNode The minimum node in the root list.
  228. * @return The heap's new minimum node.
  229. */
  230. private _cut(node: Node<K, V>, parent: Node<K, V>, minNode: Node<K, V>): Node<K, V> | null {
  231. node.parent = null;
  232. parent.degree--;
  233. if (node.next === node) {
  234. parent.child = null;
  235. } else {
  236. parent.child = node.next;
  237. }
  238. this._removeNodeFromList(node);
  239. const newMinNode = this._mergeLists(minNode, node);
  240. node.isMarked = false;
  241. return newMinNode;
  242. }
  243. /**
  244. * Perform a cascading cut on a node; mark the node if it is not marked,
  245. * otherwise cut the node and perform a cascading cut on its parent.
  246. * @param node The node being considered to be cut.
  247. * @param minNode The minimum node in the root list.
  248. * @return The heap's new minimum node.
  249. */
  250. private _cascadingCut(node: Node<K, V>, minNode: Node<K, V> | null): Node<K, V> | null {
  251. const parent = node.parent;
  252. if (parent) {
  253. if (node.isMarked) {
  254. minNode = this._cut(node, parent, <Node<K, V>>minNode);
  255. minNode = this._cascadingCut(parent, minNode);
  256. } else {
  257. node.isMarked = true;
  258. }
  259. }
  260. return minNode;
  261. }
  262. /**
  263. * Merge all trees of the same order together until there are no two trees of
  264. * the same order.
  265. * @param minNode The current minimum node.
  266. * @return The new minimum node.
  267. */
  268. private _consolidate(minNode: Node<K, V>): Node<K, V> | null {
  269. const aux = [];
  270. tmpIt.reset(minNode);
  271. while (tmpIt.hasNext()) {
  272. let current = tmpIt.next();
  273. // If there exists another node with the same degree, merge them
  274. let auxCurrent = aux[current.degree];
  275. while (auxCurrent) {
  276. if (this._compare(current, auxCurrent) > 0) {
  277. const temp = current;
  278. current = auxCurrent;
  279. auxCurrent = temp;
  280. }
  281. this._linkHeaps(auxCurrent, current);
  282. aux[current.degree] = null;
  283. current.degree++;
  284. auxCurrent = aux[current.degree];
  285. }
  286. aux[current.degree] = current;
  287. }
  288. let newMinNode = null;
  289. for (let i = 0; i < aux.length; i++) {
  290. const node = aux[i];
  291. if (node) {
  292. // Remove siblings before merging
  293. node.next = node;
  294. node.prev = node;
  295. newMinNode = this._mergeLists(newMinNode, node);
  296. }
  297. }
  298. return newMinNode;
  299. }
  300. /**
  301. * Removes a node from a node list.
  302. * @param node The node to remove.
  303. */
  304. private _removeNodeFromList(node: Node<K, V>): void {
  305. const prev = node.prev;
  306. const next = node.next;
  307. prev.next = next;
  308. next.prev = prev;
  309. node.next = node;
  310. node.prev = node;
  311. }
  312. /**
  313. * Links two heaps of the same order together.
  314. *
  315. * @private
  316. * @param max The heap with the larger root.
  317. * @param min The heap with the smaller root.
  318. */
  319. private _linkHeaps(max: Node<K, V>, min: Node<K, V>): void {
  320. this._removeNodeFromList(max);
  321. min.child = this._mergeLists(max, min.child);
  322. max.parent = min;
  323. max.isMarked = false;
  324. }
  325. /**
  326. * Merge two lists of nodes together.
  327. *
  328. * @private
  329. * @param a The first list to merge.
  330. * @param b The second list to merge.
  331. * @return The new minimum node from the two lists.
  332. */
  333. private _mergeLists(a: Node<K, V> | null, b: Node<K, V> | null): Node<K, V> | null {
  334. if (!a) {
  335. if (!b) {
  336. return null;
  337. }
  338. return b;
  339. }
  340. if (!b) {
  341. return a;
  342. }
  343. const temp = a.next;
  344. a.next = b.next;
  345. a.next.prev = a;
  346. b.next = temp;
  347. b.next.prev = b;
  348. return this._compare(a, b) < 0 ? a : b;
  349. }
  350. /**
  351. * Gets the size of a node list.
  352. * @param node A node within the node list.
  353. * @return The size of the node list.
  354. */
  355. private _getNodeListSize(node: Node<K, V>): number {
  356. let count = 0;
  357. let current = node;
  358. do {
  359. count++;
  360. if (current.child) {
  361. count += this._getNodeListSize(current.child);
  362. }
  363. current = current.next;
  364. } while (current !== node);
  365. return count;
  366. }
  367. }