堆排序的思想借助了二叉排序树,时间复杂度:O(NlgN),空间复杂度O(N)。
首先需要构建堆,堆分为大顶堆和小顶堆,如果是大顶堆,任意一个元素,满足arr[i] >=arr[2*i +1] && arr[i] >=arr[2*i+2];小顶堆满足arr[i] <=arr[2*i+1] && arr[i] <= arr[2*i+2];
堆本质上是一个完全二叉树,所以构建堆的时候,可以借助二叉树递归构建办法,构建堆的代码有:
private void buildMinHeap(int[] arr, int size, int index){
int left = 2*index + 1;
int right = 2*index + 2;
// 这里假设index就是最小的元素值,然后和孩子比较
int min = index;
// 左孩子小,需要调整和左孩子的关系
if(left < size && arr[left] <= arr[min]){
min = left;
}
// 右孩子小,调整右孩子
if(right < size && arr[right] <= arr[min]){
min = right;
}
// 表示有调整,需要交换孩子与父节点的位置
if(min != index){
int tmp = arr[min];
arr[min] = arr[index];
arr[index] = tmp;
// 这个时候,调整arr[min]后,很有可能堆不满足小顶堆,所以递归判断
buildMinHeap(arr, size, min);
}
}
构建大顶堆,则在比较的时候相反就行
private void buildMaxHeap(int[] arr, int size, int index){
int left = 2 * index + 1;
int right = 2 * index + 2;
int max= index;
if(left < size && arr[left] >= arr[max]){
max = left;
}
if(right < size && arr[right] >= arr[max]){
max = right;
}
if(max != index){
int tmp = arr[max];
arr[max] = arr[index];
arr[index] = tmp;
buildMaxHeap(arr, size, max);
}
}
用堆排序的基本思想:
构建完堆以后, 开始做排序。因为堆顶元素具有特殊性(最大或者最小),所以第一次比较用数组最后一位,与堆顶元素比较,可以确定最后一位是有序的;然后调整堆,用倒数第二位与堆顶元素比较,得到倒数第二位和最后一位构成一个有序的数组;依次循环,直到数组元素第一个比较完成。
在构建堆的时候,因为左右孩子是2倍关系,所以调整堆只需要数组长度的一半遍历就行。
public static void main(String[] args) {
int[] arr = new int[]{20,3,5,10,7,9, 11,13,15,12};
for(int i = arr.length/2 -1; i>=0; i--){
minHeap(arr, arr.length, i);
}
for(int i = arr.length-1; i > 0; i--) {
int temp = arr[0];//最前面的一个
arr[0] = arr[i];//最后一个
arr[i] = temp;
//调整后再进行小顶堆调整
minHeap(arr, i, 0);
}
}