Skip to content

堆 ​

基础与数据结构

说明 ​

维持父节点不大于子节点的最小堆;插入与取最小值都是 O(log n)。

分析 ​

最小堆只保证根是最小值,不保证整个切片有序。Push 沿父节点向上调整,Pop 把末尾元素放到根后沿较小子节点向下调整。

最小堆只要求父值不大于孩子,兄弟间不必有序。删除根后把末尾放到根,再沿较小孩子向下恢复约束;每次只走一条树高路径。读取最小值是O(1),删除并修复才是O(log n)。

查看图表代码

适用前提与边界 ​

优先队列和 Top K 常用堆;访问任意非根元素仍可能要线性查找。 空堆不能Pop;堆只保证父子大小关系,不支持直接通过下标找到某个指定值。

示例输入与调用 ​

go
h := new(MinHeap)
	h.Push(5)
	h.Push(2)
	fmt.Println(h.Pop())

运行输出 ​

text
2

完整 Go 示例 ​

go
package main

import "fmt"

type MinHeap []int

func (h *MinHeap) Push(x int) {
	*h = append(*h, x)
	for i := len(*h) - 1; i > 0; {
		p := (i - 1) / 2
		if (*h)[p] <= (*h)[i] {
			break
		}
		(*h)[p], (*h)[i] = (*h)[i], (*h)[p]
		i = p
	}
}
func (h *MinHeap) Pop() int {
	out := (*h)[0]
	last := (*h)[len(*h)-1]
	*h = (*h)[:len(*h)-1]
	if len(*h) == 0 {
		return out
	}
	(*h)[0] = last
	for i := 0; 2*i+1 < len(*h); {
		c := 2*i + 1
		if c+1 < len(*h) && (*h)[c+1] < (*h)[c] {
			c++
		}
		if (*h)[i] <= (*h)[c] {
			break
		}
		(*h)[i], (*h)[c] = (*h)[c], (*h)[i]
		i = c
	}
	return out
}

func main() {
	h := new(MinHeap)
	h.Push(5)
	h.Push(2)
	fmt.Println(h.Pop())
}

继续阅读