堆排序是一种基于比较排序的另一种排序算法,它采用了一种近似完全二叉树的二叉堆数据结构。算法实现兼容了插入排序的空间原址性(即只需要有限个额外的存储空间)和归并排序的优良时间复杂度。
伪代码如下:
HEAPSORT(A)
BUILD-MAX-HEAP(A)
for i = A.length downto 2
exchange A[1] with A[i]
A.heap-size = A.heap-size - 1
MAX-HEAPIFY(A, 1)
BUILD-MAX-HEAP(A)
A.heap-size = A.length
for i = floor(A.length / 2) downto 1
MAX-HEAPIFY(A, i)
MAX-HEAPIFY(A, i)
l = LEFT(i)
r = RIGHT(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)
分析:
a.堆排序的核心子程序就是MAX-HEAPIFY(A, i),称作最大堆的维护。输入为数组A,和一个下标i,i的左孩子和右孩子都满足最大堆的性质,但A[i]可能小于其孩子,于是需要重新定位A[i]的位置,使其保持最大堆的性质。代码过程为:先找出A[i],A[left[i]],A[right[i]]的最大值,然后将最大值与A[i]交换。然后递归的交换,到最后每一个节点i都满足 A[left(i)]≤A[i] , A[right(i)]≤A[i] 。
b.堆排序首先要创建一个最大堆。在子程序BUILD-MAX-HEAP(A)中,由于A(n/2+1..n)中的元素都是树的叶结点,所以只需要把前n/2个数插入到这个最大堆中,然后每插入一个数进行最大堆维护,当这n/2个数插完后,所得的数组就是一个最大堆。
c.堆排序主程序,先把所要排序的数组转化成最大堆,由于根位置的数就是最大的数,所以每次取根上的数放在数组的最后面,然后其余n-1个数维护后又成为最大堆,再取此时根上的数,直到只剩最后一个数,所得到的数组就是排好序的数组。
d.最大堆维护的时间复杂度为 T(n)=O(lgn) ,因为每个孩子的子树的大小至多为 2n/3 ,节点左右孩子的高度至多差1,所以 T(n)≤T(2n/3)+θ(1) ,得出 T(n)=O(lgn) 。建堆需要调用 n/2 次堆维护,所以需要 O(nlgn) 。所以堆排序总时间为:调用一次建堆, n−1 次堆维护。所以总共时间复杂度为 O(nlgn) 。
C++代码实现
#include <iostream>
using namespace std;
void max_heapify(int*, int, int);
void heapsort(int*, int);
int main()
{
int A[] = {2, 3, 6, 23, 3, 14, 0, 7, 32, 5, 3};
int length = sizeof(A)/sizeof(int);
int heap_size = length;
heapsort(A, heap_size);
for(int i = 0; i < length; i++)
{
cout<<A[i]<<" ";
}
cout<<endl;
return 0;
}
void max_heapify(int* A, int i, int heap_size)
{
int l = i * 2 + 1;
int r = l + 1;
int largest;
if(l < heap_size && A[l] > A[i])
largest = l;
else largest = i;
if(r < heap_size && A[r] > A[largest])
largest = r;
if(largest != i)
{
int t = A[i];
A[i] = A[largest];
A[largest] = t;
max_heapify(A, largest, heap_size);
}
}
void heapsort(int* A, int heap_size)
{
int length = heap_size;//这里用length = sizeof(A)/sizeof(int)得出length等于1
for(int i = length/2 - 1; i >= 0; i--)
{
max_heapify(A, i, heap_size);
}
for(int i = length-1; i > 0; i--)
{
int t = A[0];
A[0] = A[i];
A[i] = t;
heap_size--;
max_heapify(A, 0, heap_size);
}
}