Add Heap.

This commit is contained in:
Oleksii Trekhleb 2018-03-30 08:03:26 +03:00
parent 1801b6f6d7
commit 09100eab44
4 changed files with 176 additions and 0 deletions

View File

@ -8,6 +8,7 @@
2. [Queue](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/queue) 2. [Queue](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/queue)
3. [Stack](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/stack) 3. [Stack](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/stack)
4. [Hash Table](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/hash-table) 4. [Hash Table](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/hash-table)
5. [Heap](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/heap)
## [Algorithms](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms) ## [Algorithms](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms)

View File

@ -0,0 +1,118 @@
export default class MinHeap {
constructor() {
// Array representation of the heap.
this.heapContainer = [];
}
static getLeftChildIndex(parentIndex) {
return (2 * parentIndex) + 1;
}
static getRightChildIndex(parentIndex) {
return (2 * parentIndex) + 2;
}
static getParentIndex(childIndex) {
return Math.floor((childIndex - 1) / 2);
}
static hasParent(childIndex) {
return this.getParentIndex(childIndex) >= 0;
}
hasLeftChild(parentIndex) {
return MinHeap.getLeftChildIndex(parentIndex) < this.heapContainer.length;
}
hasRightChild(parentIndex) {
return MinHeap.getRightChildIndex(parentIndex) < this.heapContainer.length;
}
leftChild(parentIndex) {
return this.heapContainer[MinHeap.getLeftChildIndex(parentIndex)];
}
rightChild(parentIndex) {
return this.heapContainer[MinHeap.getRightChildIndex(parentIndex)];
}
parent(childIndex) {
return this.heapContainer[MinHeap.getParentIndex(childIndex)];
}
swap(indexOne, indexTwo) {
const tmp = this.heapContainer[indexTwo];
this.heapContainer[indexTwo] = this.heapContainer[indexOne];
this.heapContainer[indexOne] = tmp;
}
peek() {
if (this.heapContainer.length === 0) {
return null;
}
return this.heapContainer[0];
}
poll() {
if (this.heapContainer.length === 0) {
return null;
}
if (this.heapContainer.length === 1) {
return this.heapContainer.pop();
}
const item = this.heapContainer[0];
// Move the last element from the end to the head.
this.heapContainer[0] = this.heapContainer.pop();
this.heapifyDown();
return item;
}
add(item) {
this.heapContainer.push(item);
this.heapifyUp();
}
heapifyUp() {
let currentIndex = this.heapContainer.length - 1;
while (
MinHeap.hasParent(currentIndex) &&
this.parent(currentIndex) > this.heapContainer[currentIndex]
) {
this.swap(currentIndex, MinHeap.getParentIndex(currentIndex));
currentIndex = MinHeap.getParentIndex(currentIndex);
}
}
heapifyDown() {
let currentIndex = 0;
let nextIndex = 0;
while (this.hasLeftChild(currentIndex)) {
if (
this.hasRightChild(currentIndex) &&
this.leftChild(currentIndex) > this.rightChild(currentIndex)
) {
nextIndex = MinHeap.getRightChildIndex(currentIndex);
} else {
nextIndex = MinHeap.getLeftChildIndex(currentIndex);
}
if (this.heapContainer[currentIndex] < this.heapContainer[nextIndex]) {
break;
}
this.swap(currentIndex, nextIndex);
currentIndex = nextIndex;
}
}
toString() {
return this.heapContainer.toString();
}
}

View File

@ -0,0 +1 @@
# Heap

View File

@ -0,0 +1,56 @@
import MinHeap from '../MinHeap';
describe('MinHeap', () => {
it('should create an empty min heap', () => {
const minHeap = new MinHeap();
expect(minHeap).toBeDefined();
expect(minHeap.peek()).toBeNull();
});
it('should add items to the heap and heapify it up', () => {
const minHeap = new MinHeap();
minHeap.add(5);
expect(minHeap.peek()).toBe(5);
expect(minHeap.toString()).toBe('5');
minHeap.add(3);
expect(minHeap.peek()).toBe(3);
expect(minHeap.toString()).toBe('3,5');
minHeap.add(10);
expect(minHeap.peek()).toBe(3);
expect(minHeap.toString()).toBe('3,5,10');
minHeap.add(1);
expect(minHeap.peek()).toBe(1);
expect(minHeap.toString()).toBe('1,3,10,5');
});
it('should poll items from the heap and heapify it down', () => {
const minHeap = new MinHeap();
minHeap.add(5);
minHeap.add(3);
minHeap.add(10);
minHeap.add(1);
expect(minHeap.toString()).toBe('1,3,10,5');
expect(minHeap.poll()).toBe(1);
expect(minHeap.toString()).toBe('3,5,10');
expect(minHeap.poll()).toBe(3);
expect(minHeap.toString()).toBe('5,10');
expect(minHeap.poll()).toBe(5);
expect(minHeap.toString()).toBe('10');
expect(minHeap.poll()).toBe(10);
expect(minHeap.toString()).toBe('');
expect(minHeap.poll()).toBeNull();
expect(minHeap.toString()).toBe('');
});
});