茶艺师学算法打卡16:堆与堆排序
学习笔记
堆
堆是一种数据结构,能 时间取出堆顶元素。
堆顶元素是整个堆元素的最大值,那这叫做大根堆;是最小值就是小跟堆。
成为堆,至少要满足两个条件:
- 本身得是完全二叉树(因此也是能存为数组)
- 有子节点的元素,都要么大于等与子节点(大根堆),都要么小于等于子节点(小根堆)
堆支持的操作有(假设该堆是数组版)
- 往堆里插入元素
新元素直接进数组最尾部,然后按照堆的性质与自己的父节点换位(从下至上堆化) - 删除堆顶元素 堆顶元素与数组最尾部元素换位,这时堆顶元素就可以删除了,接着再把位于堆顶位置的数组最尾部元素,按照堆的性质与自己的子节点互换(从上至下堆化)
- 删除任意元素 也是与数组最尾部元素换位,换下来的被删元素直接删掉,接着(图方便做法)从上至下堆化一次再从下至上堆化一次就好了
堆排序
堆排序是原地排序,且时间复杂度与快速排序相当,也是 。 整个过程分两步,建堆与排序。
- 建堆 而且是原地(原数组)建堆,毕竟是用数组存的,里面的元素按照堆化的规则互相换位
- 排序 就参考大顶堆出堆顶的过程,一直持续出堆顶至堆空了,这时就能得到排好序的序列
堆的应用示例
- 优先队列
- 求 TopK
- 求中位数和百分为数
go 语言里的堆实现示例
type minHeap []*ListNode // 链表版
func (h minHeap) Len() int {return len(h)}
func (h minHeap) Less(i, j int)bool {return h[i].Val < h[j].Val}
func (h minHeap) Swap(i, j int) {h[i], h[j] = h[j], h[i]}
func (h *minHeap) Push(x interface{}) {
*h = append(*h, x.(*ListNode))
}
func (h *minHeap) Pop() interface{} {
old := *h
n := len(old)
x := old[n - 1]
*h = old[0 : n - 1]
return x
}
//在用的时候:
//Len 直接是h.Len() 留意一下在前面对应的是 func (h minHeap) Len()
//Pop 则是heap.Pop(h) 留意一下在前面对应的是 func (h *minHeap) Pop() interface{}
//因为这里是链表版的,完整的取头是 tmp := heap.Pop(h).(*ListNode)
//Push 则是heap.Push(h, __) 留意一下在前面对应的是 func (h *minHeap) Push(x interface{})