Skip to content

Commit ed9bbaa

Browse files
author
Isaac Ramirez
committed
- implement Heap Sort Algorithm
1 parent 6301fc1 commit ed9bbaa

File tree

4 files changed

+232
-5
lines changed

4 files changed

+232
-5
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
const Heap = require('./heap-sort')
2+
const { StdIn } = require('../../libs')
3+
4+
/**
5+
* Heap Sort Test Client.
6+
* @memberof module:TestClients
7+
* @see page: 324.
8+
* @see [edu.princeton.cs.algs4.Heap.java]{@link https://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/Heap.java.html}
9+
*/
10+
class HeapSortClient {
11+
/**
12+
* Runs the Heap Sort Algorithm
13+
* with the input provided.
14+
* @example <caption>Tiny Example</caption>
15+
* {@lang bash}
16+
* $ ./client HeapSortClient < algs4-data/tiny.txt
17+
* A E E L M O P R S T X
18+
* @example <caption>Words3 Example</caption>
19+
* {@lang bash}
20+
* $ ./client HeapSortClient < algs4-data/words3.txt
21+
* all bad bed bug dad ... yes yet zoo
22+
*/
23+
static main () {
24+
let array = []
25+
26+
// read all strings from standard input.
27+
StdIn.read()
28+
.on('line', line => {
29+
array = array.concat(line.trim().split(' '))
30+
})
31+
.on('close', () => {
32+
Heap.sort(array)
33+
34+
if (!Heap.isSorted(array)) {
35+
throw new Error('array is NOT sorted')
36+
}
37+
38+
Heap.show(array)
39+
})
40+
}
41+
}
42+
43+
module.exports = { HeapSortClient }
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
const { GenericSort } = require('../../abstracts')
2+
3+
/**
4+
* Heap Sort Algorithm.
5+
* @augments GenericSort
6+
* @memberof module:Algorithms
7+
* @see page: 324.
8+
* @see [edu.princeton.cs.algs4.Heap.java]{@link https://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/Heap.java.html}
9+
*/
10+
class Heap extends GenericSort {
11+
/**
12+
* Implementation of Heap Sort algorithm.
13+
* @param {Array<*>} a - The array of values to be sorted.
14+
* @param {ComparatorFn} [comparator] - The comparator function.
15+
*/
16+
static sort (a, comparator) {
17+
let n = a.length
18+
19+
// constructs the max heap from the first half of the array
20+
for (let k = Math.floor(n / 2); k >= 1; k--) {
21+
this.sink(a, k, n, comparator)
22+
}
23+
24+
// sort down
25+
while (n > 1) {
26+
// decrement indices by 1 so the array
27+
// can be sorted from a[0] to a[n - 1]
28+
this.exchange(a, 1 - 1, n - 1)
29+
this.sink(a, 1, --n)
30+
}
31+
}
32+
33+
/**
34+
* Sink algorithm. Restores the heap order by exchanging the node `k`
35+
* down to the tree until is no longer smaller than any of its children.
36+
* @param {Array<*>} a - The array of values treated also as the binary heap.
37+
* @param {number} k - The index of the heap to sink.
38+
* @param {number} n - The max length of the heap in which sink should run.
39+
* @param {ComparatorFn} [comparator] - The comparator function.
40+
*/
41+
static sink (a, k, n, comparator) {
42+
while (2 * k <= n) {
43+
let j = 2 * k
44+
45+
// decrement indices by 1 so the array
46+
// can be sorted from a[0] to a[n - 1]
47+
if (j < n && this.less(a[j - 1], a[j + 1 - 1], comparator)) {
48+
j++
49+
}
50+
51+
// decrement indices by 1 so the array
52+
// can be sorted from a[0] to a[n - 1]
53+
if (!this.less(a[k - 1], a[j - 1], comparator)) {
54+
break
55+
}
56+
57+
// decrement indices by 1 so the array
58+
// can be sorted from a[0] to a[n - 1]
59+
this.exchange(a, k - 1, j - 1)
60+
61+
k = j
62+
}
63+
}
64+
}
65+
66+
module.exports = Heap
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
const Heap = require('./heap-sort')
2+
const { newArrayOf } = require('../../utils')
3+
const { StdRandom } = require('../../libs')
4+
5+
describe('Unit Tests: HeapSort', () => {
6+
describe('Heap.sort()', () => {
7+
it('should sort an ordered array', () => {
8+
const orderedArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
9+
const expectedArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
10+
11+
Heap.sort(orderedArray)
12+
13+
expect(orderedArray).toEqual(expectedArray)
14+
})
15+
16+
it('should sort a reversed array', () => {
17+
const reversedArray = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
18+
const expectedArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
19+
20+
Heap.sort(reversedArray)
21+
22+
expect(reversedArray).toEqual(expectedArray)
23+
})
24+
25+
it('should sort an unordered array', () => {
26+
const unorderedArray = [0, 9, 5, 2, 1, 8, 7, 6, 4, 3]
27+
const expectedArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
28+
29+
Heap.sort(unorderedArray)
30+
31+
expect(unorderedArray).toEqual(expectedArray)
32+
})
33+
34+
it('should sort an array with all equal values', () => {
35+
const allEqualArray = [9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
36+
const expectedArray = [9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
37+
38+
Heap.sort(allEqualArray)
39+
40+
expect(allEqualArray).toEqual(expectedArray)
41+
})
42+
43+
it('should sort a small random array', () => {
44+
const n = CONFIG.SMALL_ARRAY_LENGTH
45+
const array = newArrayOf(n, () => StdRandom.uniform(n))
46+
47+
Heap.sort(array)
48+
49+
expect(Heap.isSorted(array)).toBeTrue()
50+
})
51+
52+
it('should sort a medium random array', () => {
53+
const n = CONFIG.MEDIUM_ARRAY_LENGTH
54+
const array = newArrayOf(n, () => StdRandom.uniform(n))
55+
56+
Heap.sort(array)
57+
58+
expect(Heap.isSorted(array)).toBeTrue()
59+
})
60+
61+
it('should sort a large random array', () => {
62+
const n = CONFIG.LARGE_ARRAY_LENGTH
63+
const array = newArrayOf(n, () => StdRandom.uniform(n))
64+
65+
Heap.sort(array)
66+
67+
expect(Heap.isSorted(array)).toBeTrue()
68+
})
69+
})
70+
})
71+
72+
describe('Explain me: HeapSort', () => {
73+
it('should perform n exchanges and mutate the array', () => {
74+
const a = [8, 9, 6, 5, 7, 4]
75+
const mutations = [[...a]] // initial state
76+
const originalExchange = Heap.exchange.bind(Heap)
77+
spyOn(Heap, 'sink').and.callThrough()
78+
spyOn(Heap, 'exchange').and.callFake((array, i, j) => {
79+
originalExchange(array, i, j)
80+
mutations.push([...array])
81+
})
82+
const expectedExchanges = [
83+
[a, 0, 1], // exch 1: 8 <-> 9 : heap construction
84+
[a, 0, 5], // exch 2: 9 <-> 4 : max goes to the end
85+
[a, 0, 1], // exch 3: 4 <-> 8 : sink
86+
[a, 1, 4], // exch 4: 4 <-> 7 :
87+
[a, 0, 4], // exch 5: 8 <-> 4 : max goes to the end
88+
[a, 0, 1], // exch 6: 4 <-> 7 : sink
89+
[a, 1, 3], // exch 7: 4 <-> 5 :
90+
[a, 0, 3], // exch 8: 7 <-> 4 : max goes to the end
91+
[a, 0, 2], // exch 9: 4 <-> 6 : sink
92+
[a, 0, 2], // exch 10: 6 <-> 4 : max goes to the end
93+
[a, 0, 1], // exch 11: 4 <-> 5 : sink
94+
[a, 0, 1] // exch 12: 5 <-> 4 : max goes to the end, sink
95+
]
96+
const expectedMutations = [
97+
[8, 9, 6, 5, 7, 4], // initial state
98+
[9, 8, 6, 5, 7, 4], // exch 1
99+
[4, 8, 6, 5, 7, 9], // exch 2
100+
[8, 4, 6, 5, 7, 9], // exch 3
101+
[8, 7, 6, 5, 4, 9], // exch 4
102+
[4, 7, 6, 5, 8, 9], // exch 5
103+
[7, 4, 6, 5, 8, 9], // exch 6
104+
[7, 5, 6, 4, 8, 9], // exch 7
105+
[4, 5, 6, 7, 8, 9], // exch 8
106+
[6, 5, 4, 7, 8, 9], // exch 9
107+
[4, 5, 6, 7, 8, 9], // exch 10
108+
[5, 4, 6, 7, 8, 9], // exch 11
109+
[4, 5, 6, 7, 8, 9] // exch 12
110+
]
111+
112+
Heap.sort(a)
113+
114+
expect(Heap.exchange.calls.allArgs()).toEqual(expectedExchanges)
115+
expect(Heap.sink).toHaveBeenCalledTimes(8)
116+
expect(mutations).toEqual(expectedMutations)
117+
})
118+
})

src/examples/test-clients/sort-compare.client.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,15 @@ class SortCompare {
7171
* For 100000 random Doubles
7272
* Quick3way is 2.0 times faster than Quick
7373
*
74-
* @example <caption>Quick vs. Heap</caption>
74+
* @example <caption>Heap vs. Quick</caption>
7575
* {@lang bash}
76-
* $ ./client SortCompare Quick Heap 100000 100
76+
* $ ./client SortCompare Heap Quick 100000 100
7777
*
78-
* Quick: 2.523999999999998
79-
* Heap: 21.244
78+
* Heap: 6.8640000000000025
79+
* Quick: 2.0819999999999985
8080
*
8181
* For 100000 random Doubles
82-
* Quick is 8.4 times faster than Heap
82+
* Heap is 0.3 times faster than Quick
8383
*
8484
* @param {...string} args - Params: `[algorithmName1, algorithmName2, n, trials]`
8585
* * @type {string} `args[0]` - Name of the first sorting algorithm.

0 commit comments

Comments
 (0)