赞
踩
对于每个节点的值都大于等于子树中每个节点值的堆,我们叫做“大顶堆”
。
对于每个节点的值都小于等于子树中每个节点值的堆,我们叫做“小顶堆”
。
完全二叉树适合用数组存储,所以堆也适合用数组存储。
因此可得,数组下标是 i 的元素,它的父节点以及左右子节点的位置分别是:
parent(i) = floor((i - 1)/2)【向下取整】
left(i) = 2i + 1
right(i) = 2i + 2
堆中比较重要的两个操作是插入一个数据和删除堆顶元素。这两个操作都要用到堆化
(heapify)。
1)插入一个数据的时候,我们把新插入的数据放到数组的最后,然后从下往上堆化;
原本存储[ 10, 7, 2, 5, 1 ],插入16后[ 10, 7, 2, 5, 1,16 ]
在数组末尾插入新数据16后不满足堆,要进行堆化(交换),向上堆化。16与2比较交换,16继续向上和10比较交换,最后蓝色状态满足堆,插入结束。
2)删除堆顶数据的时候,我们把数组中的最后一个元素放到堆顶,然后从上往下堆化。这两个操作时间复杂度都是 O(logn)。
原本存储[ 10, 7, 2, 5, 1 ],删除10后[ 1, 7, 2, 5]
删除堆顶元素,将数组末尾的数交换上来,但是目前不满足堆的特点了,所以也要进行堆化(交换),向下堆化。然后比较1和7(7和2选择较大的放到堆顶,所以此处选择1和7交换),继续堆化,1和5交换,直到该节点没有任何子节点或者它比两个子节点都要大,即图中灰色状态满足堆,结束。
小结:完全二叉树的高度为log2n ,因此,堆的删除、插入元素时间复杂度为 O(logn)。
堆排序包括建堆和排序两个操作,建堆和排序。
小结:堆排序包括建堆和排序两个操作,
建堆和排序
。建堆过程的时间复杂度是 O(n),排序过程的时间复杂度是 O(nlogn),所以,堆排序整体的时间复杂度是 O(nlogn)。
注意:堆排序和快速排序都是 O(nlogn)的算法,甚至堆排序更稳定,但是实际应用快速排序会比较多:原因是对堆顶节点进行堆化,会依次访问数组下标是 0,1,3 的元素,而不是像快速排序那样,局部顺序访问,所以,这样对 CPU 缓存是不友好的。另外堆排序比快速排序交换次数多,可以通过程序打印比较次数验证。
1、堆排序
2、优先级队列
3、求动态集合中位数
4、求第K大元素
5、cpu相应大于99%的应用等等
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。