Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit e4808a6

Browse files
authored
merge: Add MinHeap and test (#817)
* Add MinHeap and test * Add description and reference link * Adjust formatting
1 parent 54de6e5 commit e4808a6

File tree

2 files changed

+159
-0
lines changed

2 files changed

+159
-0
lines changed

‎Data-Structures/Heap/MinHeap.js‎

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/**
2+
* Min Heap is one of the two Binary Heap types (the other is Max Heap)
3+
* which maintains the smallest value of its input array on top and remaining values in loosely (but not perfectly sorted) order.
4+
*
5+
* Min Heaps can be expressed as a 'complete' binary tree structure
6+
* (in which all levels of the binary tree are filled, with the exception of the last level which must be filled left-to-right).
7+
*
8+
* However the Min Heap class below expresses this tree structure as an array
9+
* which represent the binary tree node values in an array ordered from root-to-leaf, left-to-right.
10+
*
11+
* In the array representation, the parent node-child node relationship is such that the
12+
* * parent index relative to its two children are: (parentIdx * 2) and (parent * 2 + 1)
13+
* * and either child's index position relative to its parent is: Math.floor((childIdx-1)/2)
14+
*
15+
* The parent and respective child values define much of heap behavior as we continue to sort or not sort depending on their values.
16+
* * The parent value must be less than or equal to either child's value.
17+
*
18+
* This is a condensed overview but for more information and visuals here is a nice read: https://www.geeksforgeeks.org/binary-heap/
19+
*/
20+
21+
class MinHeap {
22+
constructor (array) {
23+
this.heap = this.initializeHeap(array)
24+
}
25+
26+
/**
27+
* startingParent represents the parent of the last index (=== array.length-1)
28+
* and iterates towards 0 with all index values below sorted to meet heap conditions
29+
*/
30+
initializeHeap (array) {
31+
const startingParent = Math.floor((array.length - 2) / 2)
32+
33+
for (let currIdx = startingParent; currIdx >= 0; currIdx--) {
34+
this.sinkDown(currIdx, array.length - 1, array)
35+
}
36+
return array
37+
}
38+
39+
/**
40+
* overall functionality: heap-sort value at a starting index (currIdx) towards end of heap
41+
*
42+
* currIdx is considered to be a starting 'parent' index of two children indices (childOneIdx, childTwoIdx).
43+
* endIdx represents the last valid index in the heap.
44+
*
45+
* first check that childOneIdx and childTwoIdx are both smaller than endIdx
46+
* and check for the smaller heap value between them.
47+
*
48+
* the child index with the smaller heap value is set to a variable called swapIdx.
49+
*
50+
* swapIdx's value will be compared to currIdx (the 'parent' index)
51+
* and if swapIdx's value is smaller than currIdx's value, swap the values in the heap,
52+
* update currIdx and recalculate the new childOneIdx to check heap conditions again.
53+
*
54+
* if there is no swap, it means the children indices and the parent index satisfy heap conditions and can exit the function.
55+
*/
56+
sinkDown (currIdx, endIdx, heap) {
57+
let childOneIdx = currIdx * 2 + 1
58+
59+
while (childOneIdx <= endIdx) {
60+
const childTwoIdx = childOneIdx + 1 <= endIdx ? childOneIdx + 1 : -1
61+
const swapIdx = childTwoIdx !== -1 && heap[childTwoIdx] < heap[childOneIdx]
62+
? childTwoIdx
63+
: childOneIdx
64+
65+
if (heap[swapIdx] < heap[currIdx]) {
66+
this.swap(currIdx, swapIdx, heap)
67+
currIdx = swapIdx
68+
childOneIdx = currIdx * 2 + 1
69+
} else {
70+
return
71+
}
72+
}
73+
}
74+
75+
/**
76+
* overall functionality: heap-sort value at a starting index (currIdx) towards front of heap.
77+
*
78+
* while the currIdx's value is smaller than its parent's (parentIdx) value, swap the values in the heap
79+
* update currIdx and recalculate the new parentIdx to check heap condition again.
80+
*
81+
* iteration does not end while a valid currIdx has a value smaller than its parentIdx's value
82+
*/
83+
bubbleUp (currIdx) {
84+
let parentIdx = Math.floor((currIdx - 1) / 2)
85+
86+
while (currIdx > 0 && this.heap[currIdx] < this.heap[parentIdx]) {
87+
this.swap(currIdx, parentIdx, this.heap)
88+
currIdx = parentIdx
89+
parentIdx = Math.floor((currIdx - 1) / 2)
90+
}
91+
}
92+
93+
peek () {
94+
return this.heap[0]
95+
}
96+
97+
/**
98+
* the min heap value should be the first value in the heap (=== this.heap[0])
99+
*
100+
* firstIdx value and lastIdx value are swapped
101+
* the resulting min heap value now resides at heap[heap.length-1] which is popped and later returned.
102+
*
103+
* the remaining values in the heap are re-sorted
104+
*/
105+
extractMin () {
106+
this.swap(0, this.heap.length - 1, this.heap)
107+
const min = this.heap.pop()
108+
this.sinkDown(0, this.heap.length - 1, this.heap)
109+
return min
110+
}
111+
112+
// a new value is pushed to the end of the heap and sorted up
113+
insert (value) {
114+
this.heap.push(value)
115+
this.bubbleUp(this.heap.length - 1)
116+
}
117+
118+
// index-swapping helper method
119+
swap (idx1, idx2, heap) {
120+
const temp = heap[idx1]
121+
heap[idx1] = heap[idx2]
122+
heap[idx2] = temp
123+
}
124+
}
125+
126+
export { MinHeap }
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { MinHeap } from '../MinHeap'
2+
3+
describe('MinHeap', () => {
4+
const array = [2, 4, 10, 23, 43, 42, 39, 7, 9, 16, 85, 1, 51]
5+
let heap
6+
7+
beforeEach(() => {
8+
heap = new MinHeap(array)
9+
})
10+
11+
it('should initialize a heap from an input array', () => {
12+
expect(heap).toEqual({ 'heap': [1, 4, 2, 7, 16, 10, 39, 23, 9, 43, 85, 42, 51] }) // eslint-disable-line
13+
})
14+
15+
it('should show the top value in the heap', () => {
16+
const minValue = heap.peek()
17+
18+
expect(minValue).toEqual(1)
19+
})
20+
21+
it('should remove and return the top value in the heap', () => {
22+
const minValue = heap.extractMin()
23+
24+
expect(minValue).toEqual(1)
25+
expect(heap).toEqual({ 'heap': [2, 4, 10, 7, 16, 42, 39, 23, 9, 43, 85, 51] }) // eslint-disable-line
26+
})
27+
28+
it('should insert a new value and sort until it meets heap conditions', () => {
29+
heap.insert(15)
30+
31+
expect(heap).toEqual({ 'heap': [2, 4, 10, 7, 16, 15, 39, 23, 9, 43, 85, 51, 42] }) // eslint-disable-line
32+
})
33+
})

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /