Skip to content

Commit aa0bb50

Browse files
committed
chapter 10: [Heap]
1 parent e18ebb4 commit aa0bb50

File tree

11 files changed

+367
-1
lines changed

11 files changed

+367
-1
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Work in Progress.
1919
* 07: [Dictionaries and Hashes](https://github.com/loiane/javascript-datastructures-algorithms/tree/third-edition/examples/chapter07)
2020
* 08: [Recursion](https://github.com/loiane/javascript-datastructures-algorithms/tree/third-edition/examples/chapter08)
2121
* 09: [Trees](https://github.com/loiane/javascript-datastructures-algorithms/tree/third-edition/examples/chapter09)
22+
* 10: [Heap](https://github.com/loiane/javascript-datastructures-algorithms/tree/third-edition/examples/chapter10)
2223

2324
### Third Edition Updates
2425

src/js/data-structures/heap.js

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { Compare, defaultCompare, reverseCompare, swap } from '../util';
2+
3+
export class MinHeap {
4+
constructor(compareFn = defaultCompare) {
5+
this.compareFn = compareFn;
6+
this.heap = [];
7+
}
8+
getLeftIndex(index) {
9+
return 2 * index + 1;
10+
}
11+
getRightIndex(index) {
12+
return 2 * index + 2;
13+
}
14+
getParentIndex(index) {
15+
if (index === 0) {
16+
return undefined;
17+
}
18+
return Math.floor((index - 1) / 2);
19+
}
20+
size() {
21+
return this.heap.length;
22+
}
23+
isEmpty() {
24+
return this.size() <= 0;
25+
}
26+
clear() {
27+
this.heap = [];
28+
}
29+
find() {
30+
return this.isEmpty() ? undefined : this.heap[0];
31+
}
32+
insert(value) {
33+
if (value != null) {
34+
const index = this.heap.length;
35+
this.heap.push(value);
36+
this.siftUp(index);
37+
return true;
38+
}
39+
return false;
40+
}
41+
siftDown(index) {
42+
let element = index;
43+
const left = this.getLeftIndex(index);
44+
const right = this.getRightIndex(index);
45+
const size = this.size();
46+
if (left < size && this.compareFn(this.heap[element], this.heap[left]) > Compare.BIGGER_THAN) {
47+
element = left;
48+
}
49+
if (
50+
right < size &&
51+
this.compareFn(this.heap[element], this.heap[right]) > Compare.BIGGER_THAN
52+
) {
53+
element = right;
54+
}
55+
if (index !== element) {
56+
swap(this.heap, index, element);
57+
this.siftDown(element);
58+
}
59+
}
60+
siftUp(index) {
61+
let parent = this.getParentIndex(index);
62+
while (index > 0 && this.compareFn(this.heap[parent], this.heap[index]) > Compare.BIGGER_THAN) {
63+
swap(this.heap, parent, index);
64+
index = parent;
65+
parent = this.getParentIndex(index);
66+
}
67+
}
68+
extract() {
69+
if (this.isEmpty()) {
70+
return undefined;
71+
}
72+
if (this.size() === 1) {
73+
return this.heap.shift();
74+
}
75+
const removedValue = this.heap.shift();
76+
this.siftDown(0);
77+
return removedValue;
78+
}
79+
heapify(array) {
80+
if (array) {
81+
this.heap = array;
82+
this.heap.unshift(null); // remove all null elements
83+
}
84+
for (let i = this.size() - 1; i > 0; i--) {
85+
this.siftDown(i);
86+
}
87+
}
88+
}
89+
export class MaxHeap extends MinHeap {
90+
constructor(compareFn = defaultCompare) {
91+
super(compareFn);
92+
this.compareFn = compareFn;
93+
this.compareFn = reverseCompare(compareFn);
94+
}
95+
}

src/js/index.js

+9
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,12 @@ export { default as factorial } from './others/factorial';
4141
export { default as fibonacci } from './others/fibonacci';
4242
export { default as fibonacciIterative } from './others/fibonacci';
4343
export { default as fibonacciMemoization } from './others/fibonacci';
44+
45+
// chapter 09
46+
export { default as BinarySearchTree } from './data-structures/binary-search-tree';
47+
export { default as AVLTree } from './data-structures/avl-tree';
48+
49+
// chapter 10
50+
export { MinHeap as MinHeap } from './data-structures/heap';
51+
export { MaxHeap as MaxHeap } from './data-structures/heap';
52+
export { default as heapSort } from './data-structures/sorting/heap-sort';

src/js/sorting/heap-sort.js

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { defaultCompare, swap } from '../util';
2+
3+
function heapify(array, index, heapSize, compareFn) {
4+
let largest = index;
5+
const left = 2 * index + 1;
6+
const right = 2 * index + 2;
7+
if (left < heapSize && compareFn(array[left], array[index]) > 0) {
8+
largest = left;
9+
}
10+
if (right < heapSize && compareFn(array[right], array[largest]) > 0) {
11+
largest = right;
12+
}
13+
if (largest !== index) {
14+
swap(array, index, largest);
15+
heapify(array, largest, heapSize, compareFn);
16+
}
17+
}
18+
19+
function buildMaxHeap(array, compareFn) {
20+
for (let i = Math.floor(array.length / 2); i >= 0; i -= 1) {
21+
heapify(array, i, array.length, compareFn);
22+
}
23+
return array;
24+
}
25+
26+
export default function heapSort(array, compareFn = defaultCompare) {
27+
let heapSize = array.length;
28+
buildMaxHeap(array, compareFn);
29+
while (heapSize > 1) {
30+
swap(array, 0, --heapSize);
31+
heapify(array, 0, heapSize, compareFn);
32+
}
33+
return array;
34+
}

src/js/util.js

+10
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,13 @@ export function defaultToString(item) {
2424
}
2525
return item.toString();
2626
}
27+
28+
export function swap(array, a, b) {
29+
/* const temp = array[a];
30+
array[a] = array[b];
31+
array[b] = temp; */
32+
[array[a], array[b]] = [array[b], array[a]];
33+
}
34+
export function reverseCompare(compareFn) {
35+
return (a, b) => compareFn(b, a);
36+
}

src/ts/data-structures/graph.ts

Whitespace-only changes.

src/ts/data-structures/heap.ts

+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import { Compare, defaultCompare, ICompareFunction, reverseCompare, swap } from '../util';
2+
3+
export class MinHeap<T> {
4+
protected heap: T[] = [];
5+
6+
constructor(protected compareFn: ICompareFunction<T> = defaultCompare) {}
7+
8+
private getLeftIndex(index: number) {
9+
return 2 * index + 1;
10+
}
11+
12+
private getRightIndex(index: number) {
13+
return 2 * index + 2;
14+
}
15+
16+
private getParentIndex(index: number) {
17+
if (index === 0) {
18+
return undefined;
19+
}
20+
return Math.floor((index - 1) / 2);
21+
}
22+
23+
size() {
24+
return this.heap.length;
25+
}
26+
27+
isEmpty() {
28+
return this.size() <= 0;
29+
}
30+
31+
clear() {
32+
this.heap = [];
33+
}
34+
35+
findMinimum() {
36+
return this.isEmpty() ? undefined : this.heap[0];
37+
}
38+
39+
insert(value: T) {
40+
if (value != null) {
41+
const index = this.heap.length;
42+
this.heap.push(value);
43+
this.siftUp(index);
44+
return true;
45+
}
46+
return false;
47+
}
48+
49+
private siftDown(index: number) {
50+
let element = index;
51+
const left = this.getLeftIndex(index);
52+
const right = this.getRightIndex(index);
53+
const size = this.size();
54+
55+
if (left < size && this.compareFn(this.heap[element], this.heap[left]) === Compare.BIGGER_THAN) {
56+
element = left;
57+
}
58+
59+
if (
60+
right < size &&
61+
this.compareFn(this.heap[element], this.heap[right]) === Compare.BIGGER_THAN
62+
) {
63+
element = right;
64+
}
65+
66+
if (index !== element) {
67+
swap(this.heap, index, element);
68+
this.siftDown(element);
69+
}
70+
}
71+
72+
private siftUp(index: number): void {
73+
let parent = this.getParentIndex(index);
74+
while (index > 0 && this.compareFn(this.heap[parent], this.heap[index]) === Compare.BIGGER_THAN) {
75+
swap(this.heap, parent, index);
76+
index = parent;
77+
parent = this.getParentIndex(index);
78+
}
79+
}
80+
81+
extract() {
82+
if (this.isEmpty()) {
83+
return undefined;
84+
}
85+
if (this.size() === 1) {
86+
return this.heap.shift();
87+
}
88+
const removedValue = this.heap.shift();
89+
this.siftDown(0);
90+
return removedValue;
91+
}
92+
93+
heapify(array: T[]) {
94+
if (array) {
95+
this.heap = array;
96+
}
97+
98+
const maxIndex = Math.floor(this.size() / 2) - 1;
99+
100+
for (let i = 0; i <= maxIndex; i++) {
101+
this.siftDown(i);
102+
}
103+
104+
return this.heap;
105+
}
106+
}
107+
108+
export class MaxHeap<T> extends MinHeap<T> {
109+
constructor(protected compareFn: ICompareFunction<T> = defaultCompare) {
110+
super(compareFn);
111+
this.compareFn = reverseCompare(compareFn);
112+
}
113+
}

src/ts/index.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,14 @@ export { fibonacci as fibonacci} from './others/fibonacci';
2020
export { fibonacciIterative as fibonacciIterative} from './others/fibonacci';
2121
export { fibonacciMemoization as fibonacciMemoization} from './others/fibonacci';
2222

23-
// chapter 08
23+
// chapter 09
2424
export { default as BinarySearchTree } from './data-structures/binary-search-tree';
2525
export { default as AVLTree } from './data-structures/avl-tree';
2626

27+
// chapter 10
28+
export { MinHeap as MinHeap } from './data-structures/heap';
29+
export { MaxHeap as MaxHeap } from './data-structures/heap';
30+
2731

2832
/* import { hotPotato } from './others/hot-potato';
2933
import { palindromeChecker } from './others/palindrome-checker';
@@ -34,6 +38,7 @@ import { baseConverter, decimalToBinary } from './others/base-converter';
3438
import StackArray from './data-structures/stack-array';
3539
import Stack from './data-structures/stack';
3640
import { parenthesesChecker } from './others/balanced-symbols';
41+
import { MinHeap, MaxHeap } from './data-structures/heap';
3742
3843
3944
export {

src/ts/sorting/heap-sort.ts

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { defaultCompare, ICompareFunction, swap } from '../util';
2+
3+
function heapify(array: any[], index: number, heapSize: number, compareFn: ICompareFunction<any>) {
4+
let largest = index;
5+
const left = 2 * index + 1;
6+
const right = 2 * index + 2;
7+
8+
if (left < heapSize && compareFn(array[left], array[index]) > 0) {
9+
largest = left;
10+
}
11+
12+
if (right < heapSize && compareFn(array[right], array[largest]) > 0) {
13+
largest = right;
14+
}
15+
16+
if (largest !== index) {
17+
swap(array, index, largest);
18+
heapify(array, largest, heapSize, compareFn);
19+
}
20+
}
21+
22+
function buildMaxHeap(array: any[], compareFn: ICompareFunction<any>) {
23+
for (let i = Math.floor(array.length / 2); i >= 0; i -= 1) {
24+
heapify(array, i, array.length, compareFn);
25+
}
26+
return array;
27+
}
28+
29+
export default function heapSort(array: any[], compareFn = defaultCompare) {
30+
let heapSize = array.length;
31+
buildMaxHeap(array, compareFn);
32+
while (heapSize > 1) {
33+
swap(array, 0, --heapSize);
34+
heapify(array, 0, heapSize, compareFn);
35+
}
36+
return array;
37+
}

src/ts/util.ts

+11
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,14 @@ export function defaultToString(item: any): string {
2828
}
2929
return item.toString();
3030
}
31+
32+
export function swap(array: any[], a: number, b: number) {
33+
/* const temp = array[a];
34+
array[a] = array[b];
35+
array[b] = temp; */
36+
[array[a], array[b]] = [array[b], array[a]];
37+
}
38+
39+
export function reverseCompare<T>(compareFn: ICompareFunction<T>): ICompareFunction<T> {
40+
return (a, b) => compareFn(b, a);
41+
}

0 commit comments

Comments
 (0)