堆排序
首先介绍一下堆。堆是优先队列的一种实现方式(使用完全二叉树来实现),而完全二叉树可以通过数组来存储,因此堆的底层是一个数组。一个数组经过调整关键字顺序形成了堆。
堆排序的基本思路(以最大堆为例):
(1)建堆。将数组进行多次调整形成一个堆。
(2)将堆顶元素移至数组末尾,剩余元素继续调整形成新的堆。
(3)重复步骤(2)直到堆为空。这样首先是最大的数放在了末尾,接着是次大的数,以此类推。
因为元素组下标从0开始,所以根节点下标为0。有:i结点的左孩子2i+1,右孩子2i+2, index结点的父亲:(index-1)/2。
堆调整操作
adjust是一个调整操作,它将当前节点调整到合适的位置。最终以当前节点为根的子树是一个堆。
//堆调整操作,用于建堆
//cur为当前节点位置,n为当前堆中的元素个数-1
public static void adjust(int[]a,int cur,int n){
int temp=a[cur];
for(int i=cur*2+1;i<=n;i=2*i+1){
if(i<n&&a[i]<a[i+1]) i++;
if(a[i]<=temp) break;
a[cur]=a[i];
cur=i;
}
a[cur]=temp;
}
建堆和排序
public static void heapSort(int[] a){
int n=a.length-1;
//将元素组构建为堆
//最后一个节点下标为n,最后一个非叶节点下标为(n-1)/2。
for(int i=(n-1)/2;i>=0;--i) adjust(a,i,n);
for(int i=n;i>0;--i){
//堆中剩余元素的最大值放到数组尾部。
//完全二叉树的最后一个节点移至堆顶。
int temp=a[i];
a[i]=a[0];
a[0]=temp;
//根节点的左右子树均为堆,将根节点调整到适当位置后,整棵树仍然是一个堆。
adjust(a,0,i-1);
}
}
时间复杂度
时间复杂度为O(nlogn),由建堆的过程决定。