Skip to content

Commit 9ee7301

Browse files
committed
Initial commit
1 parent c356342 commit 9ee7301

File tree

7 files changed

+729
-0
lines changed

7 files changed

+729
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules

.npmignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules

Heap.js

+170
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
/**
2+
* Binary heap implementation in JavaScript ES6.
3+
* Author: Gaëtan Covelli
4+
* License: MIT
5+
*
6+
* peek() - O(1)
7+
* pop() - O(log n)
8+
* push() - O(log n)
9+
*
10+
* Usage:
11+
*
12+
* new Heap() - Creates an empty min heap
13+
* new Heap(Heap.MAX_PROPERTY) - Creates an empty max heap
14+
* new Heap(Heap.MIN_PROPERTY, array) - Creates a min heap from an exsiting array
15+
* new Heap(Heap.MAX_PROPERTY, array) - Creates a max heap from an exsiting array
16+
* heap.push(1) - Pushes a number to the heap
17+
* heap.push([1, 'Task number 1']) - Pushes an array with priority value and a string to track
18+
* heap.push([1, {name: 'my task'}]) - Pushes an array with priority value and an object to track
19+
* heap.peek() - Returns the top element of the heap
20+
* heap.pop() - Pops and returns the top element of the heap
21+
*
22+
* This heap implementation uses a 0-based indexing.
23+
*/
24+
module.exports = class Heap {
25+
26+
/**
27+
* Creates a new heap.
28+
*
29+
* @param {number} property - Optional. The property of the heap.
30+
* Heap.MIN_PROPERTY (default) or Heap.MAX_PROPERTY.
31+
* @param {array} array - Optional. An existing array that will get heapified.
32+
*/
33+
constructor(property, array = []) {
34+
this.elements = array;
35+
this.property = Heap.MIN_PROPERTY;
36+
37+
if(property === Heap.MAX_PROPERTY) {
38+
this.property = Heap.MAX_PROPERTY;
39+
}
40+
41+
if(this.elements.length > 0) {
42+
this._heapify();
43+
}
44+
}
45+
46+
static get MIN_PROPERTY() { return 0; }
47+
static get MAX_PROPERTY() { return 1; }
48+
49+
_getLeftChildIndex(parentIndex) {
50+
return parentIndex * 2 + 1;
51+
}
52+
53+
_getRightChildIndex(parentIndex) {
54+
return parentIndex * 2 + 2;
55+
}
56+
57+
_getParentIndex(childIndex) {
58+
return parseInt((childIndex - 1) / 2);
59+
}
60+
61+
_swap(i, j) {
62+
[this.elements[i], this.elements[j]] = [this.elements[j], this.elements[i]];
63+
}
64+
65+
/**
66+
* Returns the top element of the heap.
67+
*
68+
* @return {element} - The element at the top of the heap.
69+
*/
70+
peek() {
71+
return this.elements[0];
72+
}
73+
74+
/**
75+
* Pops and returns the top element of the heap.
76+
*
77+
* @return {element} - The element popped from the top of the heap.
78+
* It can be a number or an array whose first element is the priority value
79+
* and second element is the record tracked.
80+
*/
81+
pop() {
82+
let lastValue = this.elements.pop();
83+
let returnVal = lastValue;
84+
if(this.elements.length > 0) {
85+
returnVal = this.elements[0];
86+
this.elements[0] = lastValue;
87+
this._heapifyDown();
88+
}
89+
return returnVal;
90+
}
91+
92+
/**
93+
* Pushes a new element to the heap.
94+
*
95+
* @param {element} value - The element to be pushed to the heap.
96+
* It can be a number or an array whose first element is the priority value
97+
* and second element is the record we want to track.
98+
*
99+
* push(1); // A value
100+
* push([1, 'My task with priority value 1']); // A string
101+
* push([1, {firstname: 'Gaetan', lastname: 'Covelli'}]); // An object
102+
*/
103+
push(value) {
104+
this.elements.push(value);
105+
if(this.elements.length > 1) {
106+
this._heapifyUp(this.elements.length - 1);
107+
}
108+
}
109+
110+
_heapifyUp(index) {
111+
while(this._getParentIndex(index) >= 0) {
112+
let swapNeeded = false;
113+
let parentIndex = this._getParentIndex(index);
114+
115+
if(this.property === Heap.MIN_PROPERTY) {
116+
swapNeeded = this.elements[parentIndex] > this.elements[index];
117+
} else if(this.property === Heap.MAX_PROPERTY) {
118+
swapNeeded = this.elements[parentIndex] < this.elements[index];
119+
}
120+
121+
if(swapNeeded) {
122+
this._swap(parentIndex, index);
123+
index = parentIndex
124+
} else {
125+
break;
126+
}
127+
}
128+
}
129+
130+
_heapifyDown(index = 0) {
131+
while(this._getLeftChildIndex(index) < this.elements.length) {
132+
let indexToSwap = this._getLeftChildIndex(index);
133+
let rightChildIndex = this._getRightChildIndex(index);
134+
let isRightChildSwap = false;
135+
136+
if(this.property === Heap.MIN_PROPERTY) {
137+
isRightChildSwap = this.elements[rightChildIndex] < this.elements[indexToSwap];
138+
} else if(this.property === Heap.MAX_PROPERTY) {
139+
isRightChildSwap = this.elements[rightChildIndex] > this.elements[indexToSwap];
140+
}
141+
142+
if(rightChildIndex < this.elements.length && isRightChildSwap) {
143+
indexToSwap = rightChildIndex
144+
}
145+
146+
let swapFinished = false;
147+
if(this.property === Heap.MIN_PROPERTY) {
148+
swapFinished = this.elements[index] < this.elements[indexToSwap];
149+
} else if(this.property === Heap.MAX_PROPERTY) {
150+
swapFinished = this.elements[index] > this.elements[indexToSwap];
151+
}
152+
153+
if(swapFinished) {
154+
break;
155+
} else {
156+
this._swap(index, indexToSwap);
157+
}
158+
index = indexToSwap;
159+
}
160+
}
161+
162+
/**
163+
* Heapifies an existing array.
164+
*/
165+
_heapify() {
166+
for(let i = parseInt(this.elements.length / 2); i >= 0; i--) {
167+
this._heapifyDown(i);
168+
}
169+
}
170+
}

dist/Heap.js

+219
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
/**
2+
* @gaetancovelli/heap
3+
* Generated by babel.
4+
* Author: Gaëtan Covelli
5+
* Last Updated: Wed, 18 Jan 2017 16:06:39 GMT
6+
*/
7+
"use strict";
8+
9+
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
10+
11+
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
12+
13+
/**
14+
* Binary heap implementation in JavaScript ES6.
15+
* Author: Gaëtan Covelli
16+
* License: MIT
17+
*
18+
* peek() - O(1)
19+
* pop() - O(log n)
20+
* push() - O(log n)
21+
*
22+
* Usage:
23+
*
24+
* new Heap() - Creates an empty min heap
25+
* new Heap(Heap.MAX_PROPERTY) - Creates an empty max heap
26+
* new Heap(Heap.MIN_PROPERTY, array) - Creates a min heap from an exsiting array
27+
* new Heap(Heap.MAX_PROPERTY, array) - Creates a max heap from an exsiting array
28+
* heap.push(1) - Pushes a number to the heap
29+
* heap.push([1, 'Task number 1']) - Pushes an array with priority value and a string to track
30+
* heap.push([1, {name: 'my task'}]) - Pushes an array with priority value and an object to track
31+
* heap.peek() - Returns the top element of the heap
32+
* heap.pop() - Pops and returns the top element of the heap
33+
*
34+
* This heap implementation uses a 0-based indexing.
35+
*/
36+
module.exports = function () {
37+
38+
/**
39+
* Creates a new heap.
40+
*
41+
* @param {number} property - Optional. The property of the heap.
42+
* Heap.MIN_PROPERTY (default) or Heap.MAX_PROPERTY.
43+
* @param {array} array - Optional. An existing array that will get heapified.
44+
*/
45+
function Heap(property) {
46+
var array = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
47+
48+
_classCallCheck(this, Heap);
49+
50+
this.elements = array;
51+
this.property = Heap.MIN_PROPERTY;
52+
53+
if (property === Heap.MAX_PROPERTY) {
54+
this.property = Heap.MAX_PROPERTY;
55+
}
56+
57+
if (this.elements.length > 0) {
58+
this._heapify();
59+
}
60+
}
61+
62+
_createClass(Heap, [{
63+
key: "_getLeftChildIndex",
64+
value: function _getLeftChildIndex(parentIndex) {
65+
return parentIndex * 2 + 1;
66+
}
67+
}, {
68+
key: "_getRightChildIndex",
69+
value: function _getRightChildIndex(parentIndex) {
70+
return parentIndex * 2 + 2;
71+
}
72+
}, {
73+
key: "_getParentIndex",
74+
value: function _getParentIndex(childIndex) {
75+
return parseInt((childIndex - 1) / 2);
76+
}
77+
}, {
78+
key: "_swap",
79+
value: function _swap(i, j) {
80+
var _ref = [this.elements[j], this.elements[i]];
81+
this.elements[i] = _ref[0];
82+
this.elements[j] = _ref[1];
83+
}
84+
85+
/**
86+
* Returns the top element of the heap.
87+
*
88+
* @return {element} - The element at the top of the heap.
89+
*/
90+
91+
}, {
92+
key: "peek",
93+
value: function peek() {
94+
return this.elements[0];
95+
}
96+
97+
/**
98+
* Pops and returns the top element of the heap.
99+
*
100+
* @return {element} - The element popped from the top of the heap.
101+
* It can be a number or an array whose first element is the priority value
102+
* and second element is the record tracked.
103+
*/
104+
105+
}, {
106+
key: "pop",
107+
value: function pop() {
108+
var lastValue = this.elements.pop();
109+
var returnVal = lastValue;
110+
if (this.elements.length > 0) {
111+
returnVal = this.elements[0];
112+
this.elements[0] = lastValue;
113+
this._heapifyDown();
114+
}
115+
return returnVal;
116+
}
117+
118+
/**
119+
* Pushes a new element to the heap.
120+
*
121+
* @param {element} value - The element to be pushed to the heap.
122+
* It can be a number or an array whose first element is the priority value
123+
* and second element is the record we want to track.
124+
*
125+
* push(1); // A value
126+
* push([1, 'My task with priority value 1']); // A string
127+
* push([1, {firstname: 'Gaetan', lastname: 'Covelli'}]); // An object
128+
*/
129+
130+
}, {
131+
key: "push",
132+
value: function push(value) {
133+
this.elements.push(value);
134+
if (this.elements.length > 1) {
135+
this._heapifyUp(this.elements.length - 1);
136+
}
137+
}
138+
}, {
139+
key: "_heapifyUp",
140+
value: function _heapifyUp(index) {
141+
while (this._getParentIndex(index) >= 0) {
142+
var swapNeeded = false;
143+
var parentIndex = this._getParentIndex(index);
144+
145+
if (this.property === Heap.MIN_PROPERTY) {
146+
swapNeeded = this.elements[parentIndex] > this.elements[index];
147+
} else if (this.property === Heap.MAX_PROPERTY) {
148+
swapNeeded = this.elements[parentIndex] < this.elements[index];
149+
}
150+
151+
if (swapNeeded) {
152+
this._swap(parentIndex, index);
153+
index = parentIndex;
154+
} else {
155+
break;
156+
}
157+
}
158+
}
159+
}, {
160+
key: "_heapifyDown",
161+
value: function _heapifyDown() {
162+
var index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
163+
164+
while (this._getLeftChildIndex(index) < this.elements.length) {
165+
var indexToSwap = this._getLeftChildIndex(index);
166+
var rightChildIndex = this._getRightChildIndex(index);
167+
var isRightChildSwap = false;
168+
169+
if (this.property === Heap.MIN_PROPERTY) {
170+
isRightChildSwap = this.elements[rightChildIndex] < this.elements[indexToSwap];
171+
} else if (this.property === Heap.MAX_PROPERTY) {
172+
isRightChildSwap = this.elements[rightChildIndex] > this.elements[indexToSwap];
173+
}
174+
175+
if (rightChildIndex < this.elements.length && isRightChildSwap) {
176+
indexToSwap = rightChildIndex;
177+
}
178+
179+
var swapFinished = false;
180+
if (this.property === Heap.MIN_PROPERTY) {
181+
swapFinished = this.elements[index] < this.elements[indexToSwap];
182+
} else if (this.property === Heap.MAX_PROPERTY) {
183+
swapFinished = this.elements[index] > this.elements[indexToSwap];
184+
}
185+
186+
if (swapFinished) {
187+
break;
188+
} else {
189+
this._swap(index, indexToSwap);
190+
}
191+
index = indexToSwap;
192+
}
193+
}
194+
195+
/**
196+
* Heapifies an existing array.
197+
*/
198+
199+
}, {
200+
key: "_heapify",
201+
value: function _heapify() {
202+
for (var i = parseInt(this.elements.length / 2); i >= 0; i--) {
203+
this._heapifyDown(i);
204+
}
205+
}
206+
}], [{
207+
key: "MIN_PROPERTY",
208+
get: function get() {
209+
return 0;
210+
}
211+
}, {
212+
key: "MAX_PROPERTY",
213+
get: function get() {
214+
return 1;
215+
}
216+
}]);
217+
218+
return Heap;
219+
}();

0 commit comments

Comments
 (0)