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 | */
|
7 | function 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 | */
|
33 | BinaryHeap.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 | */
|
42 | BinaryHeap.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 | */
|
50 | BinaryHeap.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 | */
|
68 | BinaryHeap.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 | */
|
79 | BinaryHeap.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 | */
|
100 | BinaryHeap.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 | */
|
117 | BinaryHeap.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 |
|
126 | module.exports = BinaryHeap;
|