之前介绍了二叉堆的相关内容,这里继续前面的知识,介绍一下Heapify的内容,进而具体介绍另一种O(nlogn)的排序算法–堆排序。
Heapify
MAX-HEAPIFY
通过让A[i]的值在最大堆中shift down,从而使得下标i为根结点的子树重新遵循最大堆的性质。
参照《算法导论》给出相应伪码:1
2
3
4
5
6
7
8
9
10
11
12
13MAX-HEAPIFY(A, i)
l = LEFT(i)
r = RIGHT(i)
# 找到i,i的左子树的根结点,i的右子树的根结点中值最大的结点
if l <= A.heap-size and A[l] > A[i]
largest = l
else largest = i
if r <= A.heap-size and A[r] > A[largest]
largest = r
if largest != i
exchange A[i] with A[largest]
MAX-HEAPIFY(A, largest)
若值最大的结点不是i,则把最大的值跟i指定的值交换。然后继续对原值最大的结点递归进行MAX-HEAPIFY操作,若值最大的结点就是i,说明以i为根结点的子树已是最大堆,函数结束。
##BUILD-MAX-HEAP
构建最大堆,伪码:1
2
3
4BUILD-MAX-HEAP(A)
A.heap-size = A.length
for i = A.length/2 downto 1 #自底向上
MAX-HEAPIFY(A, i)
HEAPSORT
堆排序的实现,伪码:1
2
3
4
5
6HEAPSORT(A)
BUILD-MAX-HEAP(A) # 最大元素总是在根结点A[1]中
for i = A.length downto 2
exchange A[1] with A[i] # 将最大元素往后放在正确的位置i上
A.heap-size = A.heap-size - 1 # 去掉结点n
MAX-HEAPIFY(A, 1) # 维护,以保证去掉结点n后的堆还是最大堆
堆排序
实现思路
堆排序的实现思路关键就是上面HEAPIFY操作。
1.首先,构建最大堆
2.最大堆的一个性质:最大的元素就是堆顶的元素。我们每次就选择这个元素,这就像选择排序中选择的操作。我们这里不借助中间数组,直接和当前堆尾元素交换。
3.使最大元素在尾部不动,前面构成一个堆,维护这个堆,对其进行MAX-HEAPIFY,是前面变成最大堆
4.重复上述操作,在堆的规模缩小的同时,完成排序。
具体过程如下图:
实现
1 | heap_size = 0 |
备注:很多情况下都使用arr[0]来维护堆的大小(算法导论中是采用的这种方式),这里为了直接返回排序的数组,并未这样处理,响应的规律也有所改变,但大同小异。