堆排序的基本思想是:将待排序序列构造成一个大根堆或则小根堆,此时,整个序列的最大值或者最小值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值或者最小值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次大值或次小值。如此反复执行,便能得到一个有序序列了(升序就选大根堆,降序选小根堆)
步骤:1、构造初始堆。将给定无序序列构造成一个大顶堆(升序采用大顶堆,降序采用小顶堆)。
2、将堆顶元素与末尾元素进行交换,使末尾元素最大或者最小。然后继续调整堆,再将堆顶元素与末尾元素交换,得到第二大元素。如此反复进行交换、重建、交换。注意理解:交互后的队尾元素 不在参与下次堆调整。
实现代码如下:
public static void heapSortAlgorithm(int[] arr){
if(null==arr||arr.length<2) return;
//构建大根堆或小根堆 依据升序或降序需求自己定:升序就大根堆
//从最后一个非叶子节点开始n=arr.length; 最后一个叶子节点位置pos=n/2-1;
int len=arr.length;
int pos=len/2-1;
for(int i=pos;i>=0;i--){
adjustHeap(arr,i,len);
}
//调整堆 并 交换堆顶元素与末尾元素 以完成排序
for(int i=len-1;i>=0;i--){
swap(arr,0,i);
adjustHeap(arr,0,i);//此处选取i=是去除调整后的最后一个叶子的 因为已经最大 调整时不需要此数据了
}
}
private static void adjustHeap(int[] arr, int pos, int len) {
int temp=arr[pos];//先记录当前非叶子节点值
int leafPos=pos*2+1;//当前非叶子节点的第一个叶子节点下标
for(int i=leafPos;i<len;i=i*2+1){
if(i+1<len &&arr[i]<arr[i+1]){//如果左边叶子小于右边 则选取右边的
i++;
}
if(arr[i]>temp){
arr[pos]=arr[i];
pos=i;//同时修改记录当前非叶子节点变成了比他大的叶子节点
}else{
break;
}
}
arr[pos] = temp;//将temp值放到最终的位置
}
堆排序是一种选择排序,整体主要由构建初始堆、堆顶元素和末尾元素交换并重建堆组成。
堆排序时间复杂度:O(nlogn)