Skip to content

Commit

Permalink
chore(JavaScript): add max heap (MakeContributions#842)
Browse files Browse the repository at this point in the history
  • Loading branch information
Adelinked authored Sep 25, 2022
1 parent 368ec2e commit 8072446
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 0 deletions.
4 changes: 4 additions & 0 deletions algorithms/JavaScript/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,7 @@
## Recursion

- [Factorial](src/recursion/factorial.js)

## Heaps

- [Max Heap](src/heaps/max-heap.js)
155 changes: 155 additions & 0 deletions algorithms/JavaScript/src/heaps/max-heap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@

// A binary heap is a partially ordered binary tree
// that satisfies the heap property.
// The heap property specifies a relationship between parent and child nodes.
// In a max heap, all parent nodes are greater than
// or equal to their child nodes.
// Heaps are represented using arrays because
// it is faster to determine elements position and it needs
// less memory space as we don't need to maintain references to child nodes.
// An example:
// consider this max heap: [null, 47, 15, 35, 10, 3, 0, 25, 1].
// The root node is the first element 47. its children are 15 and 35.
// The general indexes formula for an element of index i are:
// the parent is at: Math.floor(i / 2)
// the left child is at: i * 2
// the right child is at: i * 2 + 1

const isDefined = (value) => value !== undefined && value !== null;

class MaxHeap {
constructor() {
this.heap = [null];
}

// Insert a new element method
// this is a recursive method, the algorithm is:
// 1. Add the new element to the end of the array.
// 2. If the element is larger than its parent, switch them.
// 3. Continue switching until the new element is either
// smaller than its parent or you reach the root of the tree.

insert(value) {
// add the new element to the end of the array
this.heap.push(value);
const place = (index) => {
const parentIndex = Math.floor(index / 2);
if (parentIndex <= 0) return;
if (this.heap[index] > this.heap[parentIndex]) {
// the switch is made here
[this.heap[parentIndex], this.heap[index]] = [
this.heap[index],
this.heap[parentIndex],
];
place(parentIndex);
}
};
// we begin the tests from the new element we added
place(this.heap.length - 1);
};

// Print heap content method
print() {
return this.heap;
};

// Remove an element from the heap
// it's also a recursive method, the algorithm will reestablish
// the heap property after removing the root:
// 1. Move the last element in the heap into the root position.
// 2. If either child of the root is greater than it,
// swap the root with the child of greater value.
// 3. Continue swapping until the parent is greater than both
// children or you reach the last level in the tree.

remove() {
// save the root value element because this method will return it
const removed = this.heap[1];
// the last element of the array is moved to the root position
this.heap[1] = this.heap[this.heap.length - 1];
// the last element is removed from the array
this.heap.splice(this.heap.length - 1, 1);

const place = (index) => {
if (index === this.heap.length - 1) return;
const child1Index = 2 * index;
const child2Index = child1Index + 1;
const child1 = this.heap[child1Index];
const child2 = this.heap[child2Index];
let newIndex = index;
// if the parent is greater than its two children
// then the heap property is respected
if (
(!isDefined(child1) || this.heap[newIndex] >= child1) &&
(!isDefined(child2) || this.heap[newIndex] >= child2)
) {
return;
}
// test if the parent is less than its left child
if (isDefined(child1) && this.heap[newIndex] < child1) {
newIndex = child1Index;
}
// test if the parent is less than its right child
if (isDefined(child2) && this.heap[newIndex] < child2) {
newIndex = child2Index;
}
// the parent is switched with the child of the biggest value
if (index !== newIndex) {
[this.heap[index], this.heap[newIndex]] = [
this.heap[newIndex],
this.heap[index],
];
place(newIndex);
}
};
// start tests from the beginning of the array
place(1);
return removed;
};

// Sort an array using a max heap
// the elements of the array to sort were previously added one by one
// to the heap using the insert method
// the sorted array is the result of removing the heap's elements one by one
// using the remove method until it is empty
sort() {
const arr = [];
while (this.heap.length > 1) {
arr.push(this.remove());
}
return arr;
};
// Verify the heap property of a given max heap
verifyHeap() {
const explore = (index) => {
if (index === this.heap.length - 1) return true;
const child1Index = 2 * index;
const child2Index = 2 * index + 1;
const child1 = this.heap[child1Index];
const child2 = this.heap[child2Index];
return (
(!isDefined(child1) ||
(this.heap[index] >= child1 && explore(child1Index))) &&
(!isDefined(child2) ||
(this.heap[index] >= child2 && explore(child2Index)))
);
};
return explore(1);
};
}

const test = new MaxHeap();
test.insert(1);
test.insert(3);
test.insert(0);
test.insert(10);
test.insert(35);
test.insert(25);
test.insert(47);
test.insert(15);
// display heap elements
console.log(test.print());
// verify heap property
console.log(test.verifyHeap());
// display the sorted array
console.log(test.sort());

0 comments on commit 8072446

Please sign in to comment.