堆和堆排序

先从堆说起,堆是一种树状结构,特点是父节点大于子节点,子节点之间不存在强制的大小关系(这一点上不同于二叉搜索树)。堆的特点允许我们在数组中按照层的顺序存储堆的所有节点。设任意一个节点的index为N,则它的两个子节点的index分别为2N和2N+1,除非此节点没有子节点。

也就是说,堆是一个优先队列。啥是优先队列呢?就是队列中的最大值或最小值永远在队列的队首,分别叫最大优先队列和最小优先队列。优先队列有啥用呢?可以用来计算巨量数据中的top K个元素。注意,用最大优先队列计算最小的top K,用最小优先队列计算最大的top K。由于优先队列并不是严格有序的,所以计算完成后要对优先队列内的元素进行一次排序。

那么,堆是怎么实现的呢?我们在分析一个树状结构时,首先要考虑的操作是插入操作和删除操作。堆作为一个队列,插入操作一定是从队尾插入,删除操作一定是从根节点删除。这就对应了两个操作,一个是上浮,另一个是下沉。上浮很简单,插入到最后一个位置,并将其与第N/2个元素进行比较,如果比第N/2个元素大,那么exchange N和N/2,用递归来做即可。下沉也是一样的,父节点与任意子节点比较,如果父节点小于子节点中较大的,交换。那么如何用上浮和下沉来完成插入和删除呢?

插入很简单,将新元素放在队尾,再将其上浮即可。删除也很简单,将尾元素的值赋予根节点,再将根节点下沉。

堆的特点决定了,堆只能局部有序,堆甚至不能保证高层的节点大于低层的节点,堆中唯一确定的就是父节点大于子节点——也就是根节点是最大的。

那么什么是堆排序呢?首先是将数组构建成堆,如何构建?只需要将从N/2到1的节点进行下沉操作即可,这样所有的非最底层节点都会进行一次下沉,留在根节点位置上的必然是最大值。为什么是从后往前下沉呢?从后往前与从前往后下沉有什么区别呢?可以做一个思维实验,从前往后下沉会将相隔1的层大小关系割裂,是不能保证最大值上浮的根节点的,只能从后往前下沉。进行完上述操作后,最大值被放在根节点,我们把最后一个值与根节点交换,再将最后一个值从堆中丢弃——这在数组中意味着将数组的长度-1。上面两个循环就能完成一次原地堆排序。当然也可以用笨办法,创新创建一个空间,将元素一个一个插入堆,再将堆顶一个一个抛出,只不过占用的空间要翻倍。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值