堆的基础知识

堆(heap)并不归属于STL容器,但是C++中priority_queue的底层机制正是由heap实现的。

  1. 思考: 为什么不用list作为priority_queue的底层机制

    解答: list插入可享常数时间,但是对于查找list中的最大最小值需要遍历整个list,其复杂度为O(n), 当然也可以改变做法,先让元素插入的时候先经过排序这一关,使得list的元素值中时有小到大(或由大到小),但是这样一来,插入就只有线性的效率。

  2. 思考:为什么不用binary search tree作为priority_queue的底层机制

    解答:比较麻烦的做法是以binary search tree(如:RB-tree)作为priority_queue的底层机制,这样以来元素的插入和极值的取得就有O(logN)的表现(当然这里指的是最好的情况,比如一般的binary search tree当严重不平衡的时候可能为O(N))。但是杀鸡用牛刀,未免小题大作,一来binary search tree的输入需要有足够的随机性,保证平衡;二来binary search tree并不容易实现。priority_queue的复杂度最好介于queue和binary search tree之间。binary heap便是完美契合。

一般我们所说的堆是二叉堆(binary heap),binary heap就是一种完全二叉树(complete binary tree)。除了最底层叶子节点外,是填满的,同时叶子节点从左到右不能有空隙。
在这里插入图片描述

堆是和链表和二叉树一样也是一种数据结构,前面说过堆实际上就是一种完全二叉树,其区别在于其内部是实现了节点之间的比较,也就是可以看作含内部比较器的完全二叉树

最大堆:节点的值大于其左右节点,用作升序排列

最小堆:节点的值小于其左右节点,用做降序排列

堆排序主要经过两部分:初始建堆,堆调整(堆排序)

建堆过程(自底向上)

建堆主要步骤如下:

  1. 将长度为n的数组对应到完全二叉树上
  2. 找到一个非叶子节点,对它进行操作,比较当前值和其左右孩子节点的值,是否满足最大/最小堆的要求,不满足则调整
  3. 依次查找下一个非叶子几点,重复步骤2,直到最后一个父节点。

如下所示,以最大堆建堆为例子

在这里插入图片描述

堆调整(堆排序)

在建堆的基础上对堆进行排序,需要记住的是有序区是从后往前插入的,也就是前面所讲的最大堆对应的是升序排列,反之对应的是降序排列。

堆排序的过程是将堆顶元素插入到有序区,将最后一个元素放入到堆顶,然后再采用上浮和下沉操作调整堆,使其满足要求,直到只剩一个元素为止。

堆的应用

解决topK问题,其复杂度为O(Nlogk), 建立一个大小为k的最小堆,然后将剩余的数依次和堆顶元素比较和进行堆调整。

拓展:topK问题可以用快排达到O(N)的时间复杂度,将在后面进行分析。

参考文献

[1]STL源码剖析

[2]博客:https://blog.csdn.net/qq_36711757/article/details/80444638

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值