堆
基本实现
增
上浮:插入一个数,只影响他的父节点/祖父结点/及上面的结点,而不影响兄弟姐妹结点。
当孩子节点比父母结点小时,交换。最坏情况交换到顶部。
删(根节点)
下沉:把最后一个的数调整到根节点,多次交换到底部保证整体结构不被破坏。
查
改
堆排序
建堆
-
1.创建堆结构体
-
2.上浮建堆O(N*logN)
-
3.下沉建堆O(N)
-
时间复杂度的推导
设总共需要换T(n)次,n为结点数。T(n)=2^0 * (h-1)+2^1 * (h-2)+...+2^h-2 * 1。其中下划线为每层需要移动的结点数,后一个因数为该层结点需要向下移动的层数。
用错位相减推导,得到
T(n)=2^h-1-h同时满足高度h=log2(n+1),代入上式得
T(n)=n+1-1-log2(n+1)≈n故下沉建堆时间复杂度为O(N)
-
调整,完成升序/降序
-
1.升序用大堆,降序用小堆
升序:从最后一个结点往前遍历,大堆每次能取到最大值,最后一个结点跟最大值交换,让堆顶下沉不破坏堆结构,直到遍历结束。此时大堆其实变成了升序的小堆。相当于pop操作。
-
这样完成的堆会成[1,2,3,4,5,6,7]:每次操作让最大值从后往前放,在调整的过程中,最小值逐渐往前对应。
-
每一次下沉需要 logN,N个数下沉,即总时间复杂度为O(N*logN)
-
降序反之。
-
2.升序用小堆,降序用大堆
升序:每次拿到堆顶,可以拿到最小值,往后遍历可以拿到次小值的前提是,后面的也得是最小堆,即第二次拿到的数必须为剩下数中的最小值。因此又得进行一次建堆,每个数字都进行建堆。时间复杂度是O(N^2),比较慢,因此不适合用这种方法。
降序反之。