package main
import (
"fmt"
)
func main() {
heap := BuildHeap([]int{33, 24, 8, 3, 1001, 15, 16, 15, 30, 17, 19})
var sortedArr []int
for {
v,ok := heap.Pop()
if !ok {
break
}
sortedArr = append(sortedArr, v)
}
fmt.Println(sortedArr)
}
// 小顶堆(完全二叉树,最下面一层的节点都集中在该层最左边的连续位置上;父节点小于子节点;所以可以用数组存放)
// 存储结构:i 为下标, 左子节点 i*2+1, 右子节点 i*2+2, 父节点 (i-1)/2
type Heap []int
// 交换位置
func (h Heap) swap(i, j int) {
h[j], h[i] = h[i], h[j]
}
// 比较节点大小
func (h Heap) less(i, j int) bool {
return h[i] < h[j]
}
// 插入
// 首先插入最末尾节点,自下而上与父节点比较,不断上升,一直到满足小顶堆规则
// 两种情况:1.一直升到堆顶;2.到某一位置时发现父节点比自己小,则停止。
func (h Heap) up(i int) {
for {
f := (i - 1) / 2
// 停止
if i == f || h.less(f, i) {
break
}
// 上升
h.swap(f, i)
i = f
}
}
func (h *Heap) Push(i int) {
*h = append(*h, i)
h.up(len(*h) - 1)
}
// 删除
// 1.将末节点和删除节点交换,然后删除末尾节点
// 2.原末端节点需要与新位置上的父节点做比较,如果小于要做 up(看上面的方法),
// 如果大于父节点,则再和子节点做比较,即 down 操作,直到该节点下降到小于最小子节点为止。与最小的子节点交换
func (h Heap) down(i int) {
for {
lson := i*2 + 1
rson := i*2 + 2
if rson >= len(h) {
break
}
if h.less(i, lson) && h.less(i, rson) {
break
}
if h.less(lson, rson) {
h.swap(i, lson)
i = lson
} else {
h.swap(i, rson)
i = rson
}
}
}
func (h *Heap) Remove(i int) (int, bool) {
if i < 0 || i > len(*h)-1 {
return 0, false
}
// 交换
tail := len(*h) - 1
h.swap(tail, i)
// 删除最后元素
x := (*h)[tail]
*h = (*h)[:tail]
// i节点下降或者上升
if i == 0 || (*h)[i] > (*h)[(i-1)/2] {
h.down(i)
} else {
h.up(i)
}
return x, true
}
// 弹出顶点
func (h *Heap) Pop() (int, bool) {
return h.Remove(0)
}
// 建堆
// 自底向上调整,不断的将最小值向上推。倒数第二层开始,从右到左
func BuildHeap(arr []int) Heap {
h := Heap(arr)
last := len(arr) - 1
// 最后节点的父节点
for i := (last - 1) / 2; i >= 0; i-- {
h.down(i)
}
return h
}