算法Go语言描述📌datastruct📌5-heap.txt
堆(heap)是一种满足特定条件的完全二叉树,
小顶堆(最小堆/小根堆)任意节点的值<=其子节点的值,
大顶堆(最大堆/大根堆)任意节点的值>=其子节点的值。

通常用数组来存储堆,下标特点:
根的下标为0,最后一个元素的下标为size-1。
任一节点下标i,其父节点p下标为(i-1)/2,左子节点l下标为2*i+1,右子节点r下标为2*i+2(即l+1)。

堆实现细节(两个操作):
	push:将新元素插入到堆的末尾,然后通过 “上浮” 操作,将其与父节点比较并交换,直到满足堆性质。
	pop:从堆中删除最大值时,首先根节点和末尾节点直接交换,再删除末尾节点,
		然后从根节点开始通过“下沉”操作,将其与子节点比较并交换,直到满足堆性质。

最大堆从空堆开始逐个插入构建的时间复杂度是O(nlogn),移除的平均时间复杂度也是O(nlogn)。
无序堆从根向下调整,或从叶向上调整,构建最大堆的时间复杂度降为O(n)。

堆可以用来实现优先队列,其中元素按照优先级进行排序,优先级高的元素先出队。
堆可以用来实现排序算法:首先将数组构建成一个堆,然后不断删除堆顶元素并将其放到数组的末尾,最终得到一个有序数组。
基于堆更加高效地解决Top-k问题:
	初始化一个小顶堆,先将数组的前k个元素依次入堆。
	从第k+1个元素开始,若当前元素大于堆顶元素,则将堆顶元素出堆,并将当前元素入堆。
	遍历完成后,堆中保存的就是最大的k个元素,堆顶元素即为第k大元素。

"container/heap"包提供了对任意类型(实现了heap.Interface接口)的堆操作。
heap.Interface接口需要实现5个方法,前三个方法即sort.Interface接口需要实现的方法:
	Len() int
	Less(i, j int) bool
	Swap(i, j int)
	Push(x any)
	Pop() any
对heap.Interface接口提供了以下方法:
func Init(h Interface)
func Push(h Interface, x any)
func Pop(h Interface) any
func Remove(h Interface, i int) any
func Fix(h Interface, i int)

========== ========== 堆实现优先队列 ========== ==========

package datastruct

import (
	"container/heap"
	"fmt"
)

type Item struct {
	Value    any
	Priority int
}

type PriorityQueue []*Item

func (pq *PriorityQueue) Push(x any) {
	*pq = append(*pq, x.(*Item))
}

func (pq *PriorityQueue) Pop() any {
	n := pq.Len()
	if n == 0 {
		return nil
	}
	end := n - 1
	item := (*pq)[end]
	(*pq)[end] = nil // don't stop the GC from reclaiming the item eventually
	*pq = (*pq)[:end]
	return item
}

func (pq PriorityQueue) Len() int {
	return len(pq)
}

func (pq PriorityQueue) Less(i, j int) bool {
	return pq[i].Priority > pq[j].Priority
}

func (pq PriorityQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
}

func ExamplePriorityQueue() {
	pq := PriorityQueue{
		{
			Value:    "apple",
			Priority: 3,
		},
		{
			Value:    "banana",
			Priority: 1,
		}, {
			Value:    "cherry",
			Priority: 5,
		},
	}
	heap.Init(&pq)
	heap.Push(&pq, &Item{
		Value:    "pear",
		Priority: 2,
	})
	heap.Push(&pq, &Item{
		Value:    "orange",
		Priority: 4,
	})
	for pq.Len() > 0 {
		v := heap.Pop(&pq).(*Item)
		fmt.Println(*v)
	} /*
		{cherry 5}
		{orange 4}
		{apple 3}
		{pear 2}
		{banana 1}
	*/
}