算法原理:
堆排序算法利用二叉堆进行排序。最大堆得到升序的数组,最小堆得到降序的数组。
堆:
堆的是二叉树的一种,实际上是数组对象。树上的节点和数组中的元素相对应,每一层从左到右填满,只有最后一层可能不满。
数组下标从1开始时,父节点下标和左右节点下标的关系为:PARENT(i) = i/2 LEFT(i) = 2 * i RIGHT(i) = 2 * i + 1
操作 描述 时间复杂度 build 建立一个空堆 O(n) insert 向堆中插入一个新元素 update 将新元素提升使其符合堆的性质 get 获取当前堆顶元素的值 O(1) delete 删除堆顶元素 heapify 使删除堆顶元素的堆再次成为堆
算法伪代码:
算法伪代码出自算法导论堆排序部分:
1. 建堆,当堆的大小为n时,堆的叶子节点的下标为n/2+1, n/2+2,...n
BUILD-MAX-HEAP(A)heap-size[A] = length[A]
for i=length(A)/2 to 1
do MAX-HEAPFY(A, i)2. 维护堆
MAX-HEAPFY(A, i)
l = LEFT(i)
r = RIGHT(i)
if l<= heap-size[A] and A[l] > A[i]
then largest = l
else largest = i
if r<= heap-size[A] and A[r] > A[largest]
then largest = r
if largest != i
then exchange A[i] - A[largest]
MAX-HEAPFY(A, largest)
3. 堆排序
HEAPSORT(A)
BUILD-MAX-HEAP(A)
for i=length[A] to 2
do exchange A[1] - A[i]
heap-size[A] = heap-size[A] - 1
MAX-HEAPFY(A, 1)
算法性能分析:
T(n) <= T(2n/3) + O(1)
得到T(n) = O(logn)
建堆(BUILD-MAX-HEAP)的时间复杂度:从最后一个非叶子节点开始使用MAX-HEAPFY向上调整整棵树,每个子树都成为一个最大堆。每次MAX-HEAPFY的时间已经推出为O(logn), 调用的次数为O(n),因此所需的时间为O(nlogn)
堆排序算法时间复杂度:首先调用BUILD-MAX-HEAP把数组调整为最大堆,需要的时间复杂度为O(nlogn)。把堆顶元素和堆的最后一个元素交换,需要的时间为O(1), 然后调整剩下的元素维护最大堆,调用n-1次MAX-HEAPFY,需要的时间复杂度为O(nlogn)。因此,堆排序的时间复杂度为O(nlogn)。
private void build(int[] A)
{
for(int i=A.length/2-1;i>=0;i--)
{
heapfy(A, i, A.length);
}
}
private void heapfy(int[] A, int i, int len)
{
int left = 2*i+1;
int right = 2*i+2;
int largest;
if(left < len && A[left]>A[i])
largest = left;
else
largest = i;
if(right < len && A[right] > A[largest])
largest = right;
if(largest != i)
{
int temp = A[i];
A[i] = A[largest];
A[largest] = temp;
heapfy(A, largest, len);
}
}
private void sort(int[] A)
{
build(A);
int size = A.length;
while(size > 0)
{
int temp = A[0];
A[0] = A[size-1];
A[size-1] = temp;
size--;
heapfy(A, 0, size);
}
}