package SortArith;
/**
* 堆排序 构建最大堆,堆顶即为最大元素,每次取出最大元素后,再重新构建堆,这样再拿出次大值,循环往返
* 注意:构建堆时需要调整每个非叶子节点,确定其为子堆的最大值;而调整堆时,只需要调整堆顶元素
* 特例1:若所给待排序数组array本身已是最大堆类型{9,7,8,6,1,4,5,2,3},可不进行构建堆,即可省去第一个for循环过程
* 特例2:若所给待排序数组array本身仅第一个元素待调整{-9,7,8,6,1,4,5,2,3},
* 可省去第一个for循环过程, 而调用adjustHeap(array,0,array.length-1),调整第一个元素即可;
* 时间复杂度:O(nlogn),其中构建堆为O(n),每次调整堆为logn
* 不稳定排序 适合个数较多的排序
* @author lwk
*
*/
public class HeapSort {
public static void main(String[] args) {
int[] array={-9,7,8,6,1,4,5,2,3};
heapSort(array);
for(int i=0;i<array.length;i++){
System.out.print(array[i] + " ");
}
}
public static void heapSort(int[] array){
if(array == null || array.length == 0){
return;
}
//从下往上,从右往左,依次调整各个非叶子节点,从而构建最大堆
for (int i = array.length/2-1; i >= 0; i--) {
adjustHeap(array,i,array.length-1);
}
//adjustHeap(array,0,array.length-1);
//此时堆顶为最大值
for (int i = array.length-1; i >=0; i--) {
//将堆顶元素逐步取出,与数组末尾值交换
//第一次循环结束,数组末尾为最大值,之后每次循环得到数组的次大值
int temp = array[0];
array[0] = array[i];
array[i] = temp;
//重新调整堆 调整元素为array[0]
adjustHeap(array,0,i-1);
}
}
/**
* 调整堆方法 待调整元素为array[index] 使 index - end 成为一个最大堆
* @param array
* @param index 待调整元素
* @param end
*/
public static void adjustHeap(int[] array, int index, int end){
//将有变动的元素与其下左右子节点反复比较,直至不再有元素交换或者已到叶子节点
for (int i = 2*index+1; i <= end; i = 2*i + 1) {
//比较左右节点的大小,找出较大的值
//注意:i=end时,表示没有右子节点,因此无需比较
if(i < end && array[i] < array[i+1]){
//若右节点较大,则下标指向右节点
i++;
}
//若待调整元素本身为三者最大值则下面均不需要再调整,退出循环
if(array[index] > array[i]){
break;
}
//否则将最大值与父节点交换
int temp = array[i];
array[i] = array[index];
array[index] = temp;
//交换后,则下一个待调整元素为i处元素,因此下次父节点仍为array[index]
//此后i = 2*i + 1,为array[index]的左子节点
index = i;
}
}
}
11-10