Heap.js.flow 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /**
  2. * Copyright (c) 2013-present, Facebook, Inc.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. *
  7. * @providesModule Heap
  8. * @typechecks
  9. * @preventMunge
  10. */
  11. 'use strict';
  12. /*
  13. * @param {*} a
  14. * @param {*} b
  15. * @return {boolean}
  16. */
  17. function defaultComparator(a, b) {
  18. return a < b;
  19. }
  20. class Heap {
  21. constructor(items, comparator) {
  22. this._items = items || [];
  23. this._size = this._items.length;
  24. this._comparator = comparator || defaultComparator;
  25. this._heapify();
  26. }
  27. /*
  28. * @return {boolean}
  29. */
  30. empty() {
  31. return this._size === 0;
  32. }
  33. /*
  34. * @return {*}
  35. */
  36. pop() {
  37. if (this._size === 0) {
  38. return;
  39. }
  40. const elt = this._items[0];
  41. const lastElt = this._items.pop();
  42. this._size--;
  43. if (this._size > 0) {
  44. this._items[0] = lastElt;
  45. this._sinkDown(0);
  46. }
  47. return elt;
  48. }
  49. /*
  50. * @param {*} item
  51. */
  52. push(item) {
  53. this._items[this._size++] = item;
  54. this._bubbleUp(this._size - 1);
  55. }
  56. /*
  57. * @return {number}
  58. */
  59. size() {
  60. return this._size;
  61. }
  62. /*
  63. * @return {*}
  64. */
  65. peek() {
  66. if (this._size === 0) {
  67. return;
  68. }
  69. return this._items[0];
  70. }
  71. _heapify() {
  72. for (let index = Math.floor((this._size + 1) / 2); index >= 0; index--) {
  73. this._sinkDown(index);
  74. }
  75. }
  76. /*
  77. * @parent {number} index
  78. */
  79. _bubbleUp(index) {
  80. const elt = this._items[index];
  81. while (index > 0) {
  82. const parentIndex = Math.floor((index + 1) / 2) - 1;
  83. const parentElt = this._items[parentIndex]; // if parentElt < elt, stop
  84. if (this._comparator(parentElt, elt)) {
  85. return;
  86. } // swap
  87. this._items[parentIndex] = elt;
  88. this._items[index] = parentElt;
  89. index = parentIndex;
  90. }
  91. }
  92. /*
  93. * @parent {number} index
  94. */
  95. _sinkDown(index) {
  96. const elt = this._items[index];
  97. while (true) {
  98. const leftChildIndex = 2 * (index + 1) - 1;
  99. const rightChildIndex = 2 * (index + 1);
  100. let swapIndex = -1;
  101. if (leftChildIndex < this._size) {
  102. const leftChild = this._items[leftChildIndex];
  103. if (this._comparator(leftChild, elt)) {
  104. swapIndex = leftChildIndex;
  105. }
  106. }
  107. if (rightChildIndex < this._size) {
  108. const rightChild = this._items[rightChildIndex];
  109. if (this._comparator(rightChild, elt)) {
  110. if (swapIndex === -1 || this._comparator(rightChild, this._items[swapIndex])) {
  111. swapIndex = rightChildIndex;
  112. }
  113. }
  114. } // if we don't have a swap, stop
  115. if (swapIndex === -1) {
  116. return;
  117. }
  118. this._items[index] = this._items[swapIndex];
  119. this._items[swapIndex] = elt;
  120. index = swapIndex;
  121. }
  122. }
  123. }
  124. module.exports = Heap;