堆排序的时间复杂度是,与插入排序相似,堆也具有空间原址性,即任何时候都只需要常数个额外的元素空间存储临时数据。
1. 堆简介:
(1)堆是一个数组,表示堆的数组A包括两个属性:A.length表示数组元素的个数,A.heap-size表示有多少个堆元素存储在该数组中。
给定一结点的下标i,可以得到其父结点、左孩子和右孩子的下标:
PARENT(i)
return
LEFT(i)
return 2i
RIGHT(i)
return 2i+1
(2)最大堆性质是指除了根以外的所有结点i都要满足:A[PARENT(i)] >=A[i],即某个结点的值最多与其父结点一样大。
堆中的结点高度为该结点到叶结点最长简单路径上边的数目。包含n个元素的堆看做一棵完全二叉树时,其堆高度为。
2. 维护堆性质
MAX-HEAPIFY是用于维护最大堆性质的过程,输入为一个数组A和一个下标i。该过程通过对A[i]的值在最大堆中“逐级下降”,从而使得以下标i为根结点的子树重新遵循最大堆的性质。
MAX-HEAPIFY(A,i)
l = LEFT(i)
r = RIGHT(i)
//选出最大结点,将其下标存储在largest中
if l <= A.heap-sizeand A[l] > A[i]
largest = l
else largest = i
if r <= A.heap-sizeand A[r] > A[largest]
largest = r
//如果A[i]最大,则以i为根结点的子树已经是最大堆,程序结束
if largest != i
exchangeA[i] with A[largest] //否则交换二值
//交换后,下标为largest的结点的值为原来的A[i],以此节点为根的子树有可能会//违反最大堆的性质,因此需要对子树递归调用
MAX-HEAPIFY(A,largest)
注意该过程的时间复杂度为,即与树高呈线性关系。
3. 建堆
采用自底向上的方法利用过程MAX-HEAPIFY可将一个大小为n=A.length的数组A[1..n]转换为最大堆。过程BUILD-MAX-HEAP对树中的其他结点都调用一次MAX-HEAPIFY。
BUILD-MAX-HEAP(A)
A.heap-size = A.length
for i = downto 1 //由于A(+1..n)中的元素都是树的叶节点
MAX-HEAPIFY(A,i)
注意每一次for循环的开始,结点i-1,i-2,…,1都是一个最大堆的根结点。
4. 堆排序算法
堆排序利用BUILD-MAX-HEAP将输入数组A[1..n](n=A.length)建成最大堆,因为数组中的最大元素总在根结点A[1]中,通过把它与A[n]交换,让该元素放到正确的位置。此时,从堆中去掉结点n,剩余的结点中,原来根的孩子仍然是最大堆,而新的根结点可能会违背最大堆的性质,因此,调用MAX-HEAPFY(A,1),从而在A[1..n-1]上构造一个新的最大堆。以此不断重复该过程。
HEAP-SORT(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)
注意HEAP-SORT的时间复杂度为。
5. 堆的应用:优先队列
优先队列是一种用来维护由一组元素构成的集合S的数据结构,其中每一个元素都有一个相关的值,称为关键字。最大优先队列的应用之一是共享计算机系统的作业调度,而最小优先队列应用之一是基于事件驱动的模拟器。下面介绍最大优先队列的集中操作。
HEAP-MAXIMUM(A) //返回最大关键字的元素
return A[1]
HEAP-EXTRACT-MAX(A) //去掉并返回S中具有最大关键字的元素
if A.heap-size < 1
error "heap underflow"
max = A[1]
A[1] = A[A.heap-size]
A.heap-size = A.heap-size -1
MAX-HEAPIFY(A,1)
return max
HEAP-INCREASE-KEY(A,i,key) //将元素i的关键字值增加到key
if key <A[i]
error"new key"
A[i] = key
while i >1 and A[PARENT(i)] < A[i]
exchangeA[i] with A[PARENT(i)]
i =PARENT(i)
MAX-HEAP-INSERT(A,key) //实现INSERT操作
A.heap-size =A.heap-size + 1
A[A.heap-size]= -
HEAP-INCREASE-KEY(A,A.heap-size,key)
下面的程序是实现最大堆排序:
voidbuild_max_heap(int *a,int len);
voidheap_sort(int *a,int len);
#include<stdio.h>
voidexchange(int *a,int i,int j)
{
a[i]^=a[j];
a[j]^=a[i];
a[i]^=a[j];
}
intleft_child(int i)
{
return (2*(i+1)-1);
}
intright_child(int i)
{
return (2*(i+1)+1-1);
}
voidmax_heapify(int *a,int len,int index)
{
int l,r;
int largest=index;
l=left_child(index);
r=right_child(index);
if ((l<len) &&(a[l]>a[largest]))
{
largest=l;
}
if ((r < len) && (a[r] >a[largest]))
{
largest=r;
}
if (largest != index)
{
exchange(a,largest,index);
max_heapify(a,len,largest);
}
}
intmain()
{
int source[]={16,4,10,14,7,9,3,2,8,1};
exchange(source,0,1);
printf("%d%d",source[0],source[1]);
printf("\n");
int i;
heap_sort(source,sizeof(source)/sizeof(source[0]));
for(i=0;i<sizeof(source)/sizeof(source[0]);i++)
{
printf("%d",source[i]);
}
printf("\n");
}
voidbuild_max_heap(int *a,int len)
{
int i;
for (i=len/2;i>=0;--i)
{
max_heapify(a,len,i);
}
for (i=0;i<len;i++)
{
printf("%d ",a[i]);
}
printf("\n");
}
voidheap_sort(int *a,int len)
{
int i;
build_max_heap(a,len);
for (i=len-1;i>=1;--i)
{
exchange(a,0,i);
max_heapify(a,i,0);
}
}