堆数据结构与堆排序

堆数据结构

堆的逻辑结构就是一颗完全二叉树(从上至下,从左到右依次编号的二叉树),底层可以使用数组实现。

堆的特点:
对于一个节点i (i是二叉树的节点的编号,或者数组的下标)
该节点的左孩子是:i * 2 + 1;
该节点的右孩子是:i * 2 + 2;
该节点的父节点是:(i -1) / 2;

大顶堆:
对于一个堆,如果所有的子树的根节点都大于他的左右子树的值,则这个堆是大顶堆。

小顶堆:
对于一个堆,如果所有的子树的根节点都小于于他的左右子树的值,则这个堆是小顶堆。

大顶堆和小顶堆常用语有序队列,比如优先级队列,定时任务队列。在java中的实现是:PriorityQueue

给定一个数组,如何构建一个大顶堆或者小顶堆
大顶堆(小顶堆类似):
1)将数组中的第一个元素取出放在堆顶。取出下一个数据和他的父节点比较,如果大于父节点则和父节点交换。如果还有父节点,继续比较交换,直到无法交换位置。
2)一次对所有的元素执行上述操作,最后得到的数据就是大顶堆。小顶堆相反比较交换。

交换比较的核心代码:

void heapInset(int num[], int index) {
    //num[index] 当前节点, num[(index - 1)/2]父节点
    while (num[index] > num[(index - 1)/2]){
        swap1(num, index, (index - 1)/2 );
        index = (index - 1) / 2;
    }
}

如:[2,5,3,7,6,4]
步骤
1)将2放在堆顶,取出5和他的父((i-1)/2=(1-1)/2=0)节点比较,大于父节点就交换,如果还有父节点继续比较交换。交换后的数组变成:
[5,2,3,7,6,4]

  1. 取出3和堆顶的5比较,小于堆顶不动。继续继续取出7和其父((3-1)/2=1)节点比较,7大于2则交换,数组变成[5,7,3,2,6,4];7还有父(0节点),继续比较交换,数组变成[7,5,3,2,6,4]

3)继续取出6和其父(2节点)比较交换,数组变成[7,6,3,2,5,4]。最后取出4和其父节点(2)比较交换,最终用数组表示的大顶堆是[7,6,4,2,5,3]。对应的二叉树结构图是:
在这里插入图片描述

堆排序

1)将一个数组转换为大(小)顶堆,然后将堆顶的数据保存到临时变量中,将数组尾部的元素和顶部的元素交换,同时size - 1;这样就吧最大(最小)值移出数组了。
2)将新的堆(不包含最大或者最小元素),最顶元素和左右子树比较交换,循环该过程,直到形成一个新的大顶堆(或者小顶堆)。在重复步骤1,直到最后所有数据都移出,则排序完成。

时间复杂度:

  1. 创建堆的过程,由于是完全二叉树,每个元素加入平均耗时是logN,N个元素就是O(N*logN)
  2. 排序过程中,移出堆顶元素后,需要对新的堆重新构造大(小)顶堆,应为构建其实是对堆顶一个元素的行为,也是logN,,最多重复N次,就是O(N * logN)
  3. 所以总的时间复杂度是O(2NlogN),消除常数项就是O(NlogN)

空间复杂度O()

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值