结构:
完全二叉树
分类
大根堆:以任意节点作为根节点的树中的最大值就是根节点
小跟堆:以任意节点作为根节点的树中的最小值就是根节点
基本操作
heapInsert:向上调整
heapIfy:向下调整
heapPop:删除并返回堆顶元素
实现原理
因为是一颗完全二叉树,所以采用数组实现。如果一个节点位置索引为i,父节点为:(i-1) / 2,左孩子:2*i +1 ,右孩子:2*i + 2
具体实现(默认实现的是小根堆)
func heapInsert(heap Interface, pos int) {
posSelf := pos
posPare := (pos - 1) / 2
for {
if !heap.Less(posSelf, posPare) {
break
}
heap.Swap(posPare, posSelf)
posSelf = posPare
posPare = (posSelf - 1) / 2
}
}
向上调整:当某个节点的元素值小于父节点时,和父节点交换,重复直到节点值不小于父节点或者当前节点已经是堆的根节点。
0的父节点还是0,利用这个特性,可以把两个边界条件整合成一个,即:当改节点小于父节点的时候就进行交换,否则就退出。
func heapIfy(heap Interface, pos int) {
size := heap.Len()
posSelf := pos
posLeft := posSelf*2 + 1
posRight := posSelf*2 + 2
var minPos int
for {
if posLeft >= size {
break
}
if posRight < size {
if heap.Less(posLeft, posRight) {
minPos = posLeft
} else {
minPos = posRight
}
} else {
minPos = posLeft
}
if heap.Less(posSelf, minPos) {
break
}
heap.Swap(minPos, posSelf)
posSelf = minPos
posLeft = posSelf*2 + 1
posRight = posSelf*2 + 2
}
}
向下调整:两个边界条件,1:该节点小于其两个子节点,2:该节点是叶节点。所以程序中上来首先判断是否为叶节点,如果是叶节点则无需向下调整,直接退出。如果不是叶节点,那么找出两个孩子中较小的一个(可能无右孩子,分情况讨论),如果较小的节点小于父节点则交换并重复,否则直接退出。
func heapPop(heap Interface) interface{} {
var ret interface{}
if heap.Len() > 0 {
ret = heap.FirstElem()
}
if ret != nil {
heap.Swap(0, heap.Len()-1)
heap.DeleteLast()
heapIfy(heap, 0)
}
return ret
}
删除堆顶并返回:如果堆为空,直接返回Nil,否则交换堆顶和堆的最后一个元素,然后删除最后一个元素,堆顶位置的元素做一个heapIfy的过程即可。