UNPKG

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