Skip to content

Commit 09100ea

Browse files
committedMar 30, 2018
Add Heap.
1 parent 1801b6f commit 09100ea

File tree

4 files changed

+176
-0
lines changed

4 files changed

+176
-0
lines changed
 

‎README.md

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
2. [Queue](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/queue)
99
3. [Stack](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/stack)
1010
4. [Hash Table](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/hash-table)
11+
5. [Heap](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/heap)
1112

1213
## [Algorithms](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms)
1314

‎src/data-structures/heap/MinHeap.js

+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
export default class MinHeap {
2+
constructor() {
3+
// Array representation of the heap.
4+
this.heapContainer = [];
5+
}
6+
7+
static getLeftChildIndex(parentIndex) {
8+
return (2 * parentIndex) + 1;
9+
}
10+
11+
static getRightChildIndex(parentIndex) {
12+
return (2 * parentIndex) + 2;
13+
}
14+
15+
static getParentIndex(childIndex) {
16+
return Math.floor((childIndex - 1) / 2);
17+
}
18+
19+
static hasParent(childIndex) {
20+
return this.getParentIndex(childIndex) >= 0;
21+
}
22+
23+
hasLeftChild(parentIndex) {
24+
return MinHeap.getLeftChildIndex(parentIndex) < this.heapContainer.length;
25+
}
26+
27+
hasRightChild(parentIndex) {
28+
return MinHeap.getRightChildIndex(parentIndex) < this.heapContainer.length;
29+
}
30+
31+
leftChild(parentIndex) {
32+
return this.heapContainer[MinHeap.getLeftChildIndex(parentIndex)];
33+
}
34+
35+
rightChild(parentIndex) {
36+
return this.heapContainer[MinHeap.getRightChildIndex(parentIndex)];
37+
}
38+
39+
parent(childIndex) {
40+
return this.heapContainer[MinHeap.getParentIndex(childIndex)];
41+
}
42+
43+
swap(indexOne, indexTwo) {
44+
const tmp = this.heapContainer[indexTwo];
45+
this.heapContainer[indexTwo] = this.heapContainer[indexOne];
46+
this.heapContainer[indexOne] = tmp;
47+
}
48+
49+
peek() {
50+
if (this.heapContainer.length === 0) {
51+
return null;
52+
}
53+
54+
return this.heapContainer[0];
55+
}
56+
57+
poll() {
58+
if (this.heapContainer.length === 0) {
59+
return null;
60+
}
61+
62+
if (this.heapContainer.length === 1) {
63+
return this.heapContainer.pop();
64+
}
65+
66+
const item = this.heapContainer[0];
67+
68+
// Move the last element from the end to the head.
69+
this.heapContainer[0] = this.heapContainer.pop();
70+
this.heapifyDown();
71+
72+
return item;
73+
}
74+
75+
add(item) {
76+
this.heapContainer.push(item);
77+
this.heapifyUp();
78+
}
79+
80+
heapifyUp() {
81+
let currentIndex = this.heapContainer.length - 1;
82+
83+
while (
84+
MinHeap.hasParent(currentIndex) &&
85+
this.parent(currentIndex) > this.heapContainer[currentIndex]
86+
) {
87+
this.swap(currentIndex, MinHeap.getParentIndex(currentIndex));
88+
currentIndex = MinHeap.getParentIndex(currentIndex);
89+
}
90+
}
91+
92+
heapifyDown() {
93+
let currentIndex = 0;
94+
let nextIndex = 0;
95+
96+
while (this.hasLeftChild(currentIndex)) {
97+
if (
98+
this.hasRightChild(currentIndex) &&
99+
this.leftChild(currentIndex) > this.rightChild(currentIndex)
100+
) {
101+
nextIndex = MinHeap.getRightChildIndex(currentIndex);
102+
} else {
103+
nextIndex = MinHeap.getLeftChildIndex(currentIndex);
104+
}
105+
106+
if (this.heapContainer[currentIndex] < this.heapContainer[nextIndex]) {
107+
break;
108+
}
109+
110+
this.swap(currentIndex, nextIndex);
111+
currentIndex = nextIndex;
112+
}
113+
}
114+
115+
toString() {
116+
return this.heapContainer.toString();
117+
}
118+
}

‎src/data-structures/heap/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Heap
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import MinHeap from '../MinHeap';
2+
3+
describe('MinHeap', () => {
4+
it('should create an empty min heap', () => {
5+
const minHeap = new MinHeap();
6+
7+
expect(minHeap).toBeDefined();
8+
expect(minHeap.peek()).toBeNull();
9+
});
10+
11+
it('should add items to the heap and heapify it up', () => {
12+
const minHeap = new MinHeap();
13+
14+
minHeap.add(5);
15+
expect(minHeap.peek()).toBe(5);
16+
expect(minHeap.toString()).toBe('5');
17+
18+
minHeap.add(3);
19+
expect(minHeap.peek()).toBe(3);
20+
expect(minHeap.toString()).toBe('3,5');
21+
22+
minHeap.add(10);
23+
expect(minHeap.peek()).toBe(3);
24+
expect(minHeap.toString()).toBe('3,5,10');
25+
26+
minHeap.add(1);
27+
expect(minHeap.peek()).toBe(1);
28+
expect(minHeap.toString()).toBe('1,3,10,5');
29+
});
30+
31+
it('should poll items from the heap and heapify it down', () => {
32+
const minHeap = new MinHeap();
33+
34+
minHeap.add(5);
35+
minHeap.add(3);
36+
minHeap.add(10);
37+
minHeap.add(1);
38+
39+
expect(minHeap.toString()).toBe('1,3,10,5');
40+
41+
expect(minHeap.poll()).toBe(1);
42+
expect(minHeap.toString()).toBe('3,5,10');
43+
44+
expect(minHeap.poll()).toBe(3);
45+
expect(minHeap.toString()).toBe('5,10');
46+
47+
expect(minHeap.poll()).toBe(5);
48+
expect(minHeap.toString()).toBe('10');
49+
50+
expect(minHeap.poll()).toBe(10);
51+
expect(minHeap.toString()).toBe('');
52+
53+
expect(minHeap.poll()).toBeNull();
54+
expect(minHeap.toString()).toBe('');
55+
});
56+
});

0 commit comments

Comments
 (0)
Please sign in to comment.