算法6.堆与堆排序

堆:

二叉堆满足二个特性:

1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。

2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。

当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆。当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆

一般用数组实现二叉堆

如果用长度为N+1的数组 A[N+1] 来表示一个大小为N的堆,不会使用A[0],把堆元素放在A[1] -A[n]中, 根节点在A[1] 中,它的左右子节点在分别在A[2]和A[3]中,位置k的结点的父结点的位置为 k/2(向下取整,设为int i = k/2 就自动向下取整了) ,而它的两个子结点的位置则分别为2k和2k+1。

如果A[0]也用上 i结点的父结点下标就为(i – 1) / 2。它的左右子结点下标分别为2 * i + 1和2 * i + 2。如第0个结点左右子结点下标分别为1和2。  (记这个吧)

堆实现优先队列有两种关键操作:

1)插入

将新元素加到数组尾,然后把这个新元素上浮(swim)到合适的位置

2)删除

删除一般就是删除最大元素,也就是根节点 A, 数组第一个

一般采取的方法是 将根节点与数组最后一个  交换,然后 下沉(sink)新根节点,   把数组最后一个给删掉,--N

堆排序

然后是堆排序

基本思想是,先把一个数组构造成一个堆,然后再反复删除最大元素

构造堆有个小窍门,假如A[0]是根节点,一共有N个元素,那么 从N/2-1到0 开始下沉,N/2到最后不用管它

然后再删除最大元素,第一次将A[0]与A[n - 1]交换,再对A[0]下沉   重新恢复堆。第二次将A[0]与A[n – 2]交换,再对A[0…n - 3]重新恢复堆,重复这样的操作直到A[0]与A[1]交换。由于每次都是将最大的数据并入到后面的有序区间,故操作完成后整个数组就有序了

由于每次重新恢复堆的时间复杂度为O(logN),共N - 1次重新恢复堆操作,再加上前面建立堆时N / 2次向下调整,每次调整时间复杂度也为O(logN)。二次操作时间相加还是O(N * logN)。故堆排序的时间复杂度为O(N * logN)。

参考资料:https://blog.csdn.net/MoreWindows/article/details/6709644

猜你喜欢

转载自blog.csdn.net/speargod/article/details/88047197