堆与堆排序—优先队列

上一节我们写了树以及二叉树的知识

http://blog.csdn.net/wtyvhreal/article/details/43487095


堆是一种特殊的完全二叉树。


所有父节点都比子节点要小,这样的完全二叉树称为最小堆,反之叫最大堆。


下图一棵完全二叉树,调整为最小堆步骤:


向下调整的代码如下:


从上面可以得到:调整堆的时间复杂度是O(logN)。


如果堆的大小为N,那么插入一个新元素所需要的时间为O(logN).

在刚刚那个最小堆里插入数值3

向上调整的代码如下:


建堆:从空的堆开始,依次往堆中插入每一个元素。整体时间复杂度是O(NlogN).


下面用O(N)复杂度来建堆。

。。。


n个元素建堆:

首先可以将这n个节点以自顶向下,从左到右的方式从1到n编码,这样就可以把这n个节点转换为一棵完全二叉树,然后从(最后一个非叶节点)第n/2个节点(n为节点总数)开始到根节点逐个处理这颗完全二叉树(最后一个非叶节点是第n/2个节点)。根据需要将当前节点向下调整,直至符合堆的特征。时间复杂度为O(N).

证明时间复杂度为O(N):


首先这个循环是从i = n/2 -> 1,也就是说这是一个bottom-up的建堆。于是,有1/2的元素向下比较了一次,有1/4的向下比较了两次,有1/8的向下比较了3次,......,1/2^k的向下比较了k次,其中1/2^k <= 1, k 约等于lg(n)。于是就有总的比较量:

T = (\sum_{k = 1}^{lg(n)}{​{1 \over {2^k}} \times k} ) * n

令 S = \sum_{k = 1}^{lg(n)}{​{1 \over {2^k}} \times k}

1/2 S = \sum_{k = 1}^{lg(n) - 1}{​{1 \over {2^{k+1}}} \times k} = {1 \over 4} + {1 \over 8} \times 2 + \cdots + {1 \over {2^{k+1}}} \times k
S - 1/2S = 1/2S = {1 \over 2} + {1 \over 4} + \cdots + {1 \over {2^k}} - {1 \over {2^{k+1}}} \times k
到这步就很明显了吧,S <= 2
于是T <= 2n => T = O(n).



堆排序的时间复杂度也是O(NlogN)。

比如从小到大排序,先建立最小堆。然后每次删除顶部元素然后调整,直到堆为空。



还有一中堆排方法,是建立最大堆,而不是上面建立的最小堆。

最大堆建立好后,最大的元素是h[1],交换h[1]和h[n],此时h[n]就是最大的元素了。然后将交换后的h[1]向下调整保持堆的特性。交换一次,n--,反复直到堆的大小变为1.此时h数组就是已经排好序了。


总结:

支持插入元素和寻找最值的数据结构称为优先队列。堆就是一种优先队列


堆还经常用来求一个数列中第K大的数,只需要建立一个大小为K的最小堆,堆顶就是第K大的数,时间复杂度O(NlogK)

(10个数找第3大的数,首先任意3个数,建成最小堆,然后从第4个数开始,与堆顶比较,小忽略,比堆顶大,则舍弃当前堆顶而将这个数作为新的堆顶,并再去维护。。。)



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值