UNPKG

3.41 kBJavaScriptView Raw
1/**
2 * An implementation of the [Binary Heap]{@link https://en.wikipedia.org/wiki/Binary_heap} data structure suitable for priority queues.
3 * @constructor
4 * @alias Splat.BinaryHeap
5 * @param {compareFunction} cmp A comparison function that determines how the heap is sorted.
6 */
7function BinaryHeap(cmp) {
8 /**
9 * The comparison function for sorting the heap.
10 * @member {compareFunction}
11 * @private
12 */
13 this.cmp = cmp;
14 /**
15 * The list of elements in the heap.
16 * @member {Array}
17 * @private
18 */
19 this.array = [];
20 /**
21 * The number of elements in the heap.
22 * @member {number}
23 * @readonly
24 */
25 this.length = 0;
26}
27/**
28 * Calculate the index of a node's parent.
29 * @param {number} i The index of the child node
30 * @returns {number}
31 * @private
32 */
33BinaryHeap.prototype.parentIndex = function(i) {
34 return Math.floor((i - 1) / 2);
35};
36/**
37 * Calculate the index of a parent's first child node.
38 * @param {number} i The index of the parent node
39 * @returns {number}
40 * @private
41 */
42BinaryHeap.prototype.firstChildIndex = function(i) {
43 return (2 * i) + 1;
44};
45/**
46 * Bubble a node up the heap, stopping when it's value should not be sorted before its parent's value.
47 * @param {number} pos The index of the node to bubble up.
48 * @private
49 */
50BinaryHeap.prototype.bubbleUp = function(pos) {
51 if (pos === 0) {
52 return;
53 }
54
55 var data = this.array[pos];
56 var parentIndex = this.parentIndex(pos);
57 var parent = this.array[parentIndex];
58 if (this.cmp(data, parent) < 0) {
59 this.array[parentIndex] = data;
60 this.array[pos] = parent;
61 this.bubbleUp(parentIndex);
62 }
63};
64/**
65 * Store a new node in the heap.
66 * @param {object} data The data to store
67 */
68BinaryHeap.prototype.insert = function(data) {
69 this.array.push(data);
70 this.length = this.array.length;
71 var pos = this.array.length - 1;
72 this.bubbleUp(pos);
73};
74/**
75 * Bubble a node down the heap, stopping when it's value should not be sorted after its parent's value.
76 * @param {number} pos The index of the node to bubble down.
77 * @private
78 */
79BinaryHeap.prototype.bubbleDown = function(pos) {
80 var left = this.firstChildIndex(pos);
81 var right = left + 1;
82 var largest = pos;
83 if (left < this.array.length && this.cmp(this.array[left], this.array[largest]) < 0) {
84 largest = left;
85 }
86 if (right < this.array.length && this.cmp(this.array[right], this.array[largest]) < 0) {
87 largest = right;
88 }
89 if (largest !== pos) {
90 var tmp = this.array[pos];
91 this.array[pos] = this.array[largest];
92 this.array[largest] = tmp;
93 this.bubbleDown(largest);
94 }
95};
96/**
97 * Remove the heap's root node, and return it. The root node is whatever comes first as determined by the {@link compareFunction}.
98 * @returns {data} The root node's data.
99 */
100BinaryHeap.prototype.deleteRoot = function() {
101 var root = this.array[0];
102 if (this.array.length <= 1) {
103 this.array = [];
104 this.length = 0;
105 return root;
106 }
107 this.array[0] = this.array.pop();
108 this.length = this.array.length;
109 this.bubbleDown(0);
110 return root;
111};
112/**
113 * Search for a node in the heap.
114 * @param {object} data The data to search for.
115 * @returns {number} The index of the data in the heap, or -1 if it is not found.
116 */
117BinaryHeap.prototype.indexOf = function(data) {
118 for (var i = 0; i < this.array.length; i++) {
119 if (this.array[i] === data) {
120 return i;
121 }
122 }
123 return -1;
124};
125
126module.exports = BinaryHeap;