堆排序(Heap Sort)是利用堆(本文使用大顶堆)进行排序的方法。它的基本思想是, 将待排序的序列构造成一个大顶堆。此时,整个序列的最大值就是堆顶的根结点。将它移走(其实就是将其与堆数组的末尾元素交换,此时末尾元素就是最大值) ,然后将剩余的 n-1 个序列重新构造成一个堆,这样就得到 n 个元素中的次小值。如此反复执行, 便能得到一个有序序列了。堆排序是一种不稳定的排序算法,复杂度O(nlogn)。
堆是具有下列性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆,或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。
大顶堆、小顶堆:
import java.util.Arrays;
//测试类
public class HeapSort {
public static void main(String[] args) {
int[]arr=new int[] {9,6,8,7,0,1,10,4,2};
heapSort(arr);
//输出:[0, 1, 2, 4, 6, 7, 8, 9, 10]
System.out.println(Arrays.toString(arr));
}
//堆排序
public static void heapSort(int[]arr) {
//开始位置是最后一个非叶子结点,即最后一个结点的父节点
int start=(arr.length-1)/2;
//调整为大顶堆
for (int i = start; i >=0; i--) {
maxHeap(arr,arr.length,i);
}
//先把数组中的第0个和堆中的最后一个数交换位置,再把前面的处理为大顶堆
for (int i = arr.length-1; i >0; i--) {
int temp=arr[0];
arr[0]=arr[i];
arr[i]=temp;
maxHeap(arr, i, 0);
}
}
//构建大顶堆
public static void maxHeap(int[] arr, int size, int index) {
// TODO Auto-generated method stub
//左子结点
int leftNode=2*index+1;
//右子结点
int rightNode=2*index+2;
int max=index;
//和两个子结点分别对比,找出最大的结点
if(leftNode<size && arr[leftNode]>arr[max])
max=leftNode;
if(rightNode<size && arr[rightNode]>arr[max])
max=rightNode;
//交换位置
if(max!=index) {
int tmp=arr[index];
arr[index]=arr[max];
arr[max]=tmp;
//交换位置以后,可能会破坏之前排好序的堆,所以,之前排好的堆需要重新调整
maxHeap(arr, size, max);
}
}
}