-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmin_heap.go
128 lines (102 loc) · 2.74 KB
/
min_heap.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package main
import (
"fmt"
)
// MinHeap is a min heap implementation that supports integer values
type MinHeap struct {
arr []int
}
// Insert adds an element to the heap
func (h *MinHeap) Insert(val int) {
h.arr = append(h.arr, val)
h.percolateUp(len(h.arr) - 1)
fmt.Printf("heap after inserting %v: %v\n", val, h.arr)
}
// Extract removes the highest priority element from the max heap
func (h *MinHeap) Extract() int {
min := h.arr[0]
fmt.Printf("extracting min: %v\n", min)
last := len(h.arr) - 1
h.swap(0, last)
// remember: slices are not arrays, but rather "flexible views into the elements of an array"
// so here, we're re-assigning the heap slice to the same underlying data but excluding the last element
h.arr = h.arr[:last]
h.percolateDown(0)
fmt.Printf("new heap: %v\n", h.arr)
return min
}
// percolateUp recursively percolates up the min heap
// swapping elements with its parent until parent >= element
func (h *MinHeap) percolateUp(i int) {
// base case: if i is root, then we're done
if i == 0 {
return
}
parent := parent(i)
// if the current element deserves to be the parent instead, swap and continue percolating
if h.arr[i] < h.arr[parent] {
h.swap(i, parent)
h.percolateUp(parent)
}
}
// percolateDown percolates down the min heap
// swapping the current element with its larger child until current >= both children
func (h *MinHeap) percolateDown(i int) {
l, r := left(i), right(i)
last := len(h.arr) - 1
// while we have at least one left child
for l <= last {
// pick the index of the smaller child (or left if only one)
var child int
if l == last {
child = l
} else if h.arr[l] <= h.arr[r] { // just pick one if they're equal
child = l
} else if h.arr[r] < h.arr[l] {
child = r
}
// swap the current element with that child if it's larger
if h.arr[i] > h.arr[child] {
h.swap(i, child)
i = child
l, r = left(i), right(i)
} else {
return
}
}
}
// swap swaps elements i and j in the min heap
func (h *MinHeap) swap(i, j int) {
h.arr[i], h.arr[j] = h.arr[j], h.arr[i]
}
// parent returns the index of the parent of the provided index i
func parent(i int) int {
return (i - 1) / 2
}
// left returns the index of the left child of the provided index i
func left(i int) int {
return (2 * i) + 1
}
// right returns the index of the right child of the provided index i
func right(i int) int {
return (2 * i) + 2
}
func main() {
// create a new min heap
heap := MinHeap{}
// heapify some data
data := []int{100, 30, 205, 12, 23, 400, 150, 12}
for _, v := range data {
heap.Insert(v)
}
fmt.Printf("data: %+v\n", heap)
// extract the min a few times
heap.Extract()
heap.Extract()
heap.Extract()
heap.Extract()
heap.Extract()
heap.Extract()
heap.Extract()
heap.Extract()
}