茶艺师学算法打卡16:堆与堆排序

102 阅读2分钟

茶艺师学算法打卡16:堆与堆排序

学习笔记

堆是一种数据结构,能 O(1)O(1) 时间取出堆顶元素。
堆顶元素是整个堆元素的最大值,那这叫做大根堆;是最小值就是小跟堆。
成为堆,至少要满足两个条件:

  • 本身得是完全二叉树(因此也是能存为数组)
  • 有子节点的元素,都要么大于等与子节点(大根堆),都要么小于等于子节点(小根堆)

堆支持的操作有(假设该堆是数组版)

  • 往堆里插入元素
    新元素直接进数组最尾部,然后按照堆的性质与自己的父节点换位(从下至上堆化)
  • 删除堆顶元素 堆顶元素与数组最尾部元素换位,这时堆顶元素就可以删除了,接着再把位于堆顶位置的数组最尾部元素,按照堆的性质与自己的子节点互换(从上至下堆化)
  • 删除任意元素 也是与数组最尾部元素换位,换下来的被删元素直接删掉,接着(图方便做法)从上至下堆化一次再从下至上堆化一次就好了

堆排序

堆排序是原地排序,且时间复杂度与快速排序相当,也是 O(nlogn)O(nlogn) 。 整个过程分两步,建堆与排序。

  • 建堆 而且是原地(原数组)建堆,毕竟是用数组存的,里面的元素按照堆化的规则互相换位
  • 排序 就参考大顶堆出堆顶的过程,一直持续出堆顶至堆空了,这时就能得到排好序的序列

堆的应用示例

  • 优先队列
  • 求 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{})