堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
1、创建大根堆,从后往前遍历所有非叶子节点(非叶子节点都有两个子节点),依次调整,得到一个大根堆,条件满足任何一个非叶子节点大于它的两个子节点。
private void createMaxHeap(int[] arr, int size) {
for (int i= arr.length / 2 - 1 ; i >= 0 ; i --){
adjustHeap(arr,i,size);
}
}
2、调整堆函数,主要算法,父节点和左右子节点对比,子节点大于父节点,则交换
/**
* 堆调整算法逻辑,非叶子节点和左右子节点比较,子节点大于则调整
*/
private void adjustHeap(int[] arr,int index, int size){
//左节点
int left = 2 * index + 1;
int right = 2 * index + 2;
int largest = index;
if(left < size && arr[left] > arr[largest]){
largest = left;
}
if(right < size && arr[right] > arr[largest]){
largest = right;
}
if(largest != index){
swap(arr,index,largest);
adjustHeap(arr , largest ,size);
}
}
3、交换函数
private void swap(int[] arr , int i ,int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
全部代码
public void main(){
int[] arr = {56,36,78,94,13,47,32,51,22,-12,-89,3,23,3,94};
long startTime = System.currentTimeMillis();
System.out.println("原始数据排序:" + Arrays.toString(arr));
heapSort(arr);
long endTime = System.currentTimeMillis();
System.out.println("最终数据排序:" + Arrays.toString(arr));
System.out.println("花费时间:" + (endTime - startTime) + "毫秒");
}
/**
* 堆排序
* @param arr
*/
private void heapSort(int[] arr){
//大根堆长度
int size = arr.length;
//创建大根堆
createMaxHeap(arr , size);
System.out.println("创建大根堆后:" + Arrays.toString(arr));
//将堆顶的元素和最后一个互换
swap(arr,0,size -1);
//大根堆长度减1,末尾存好堆顶元素就不动了
size -- ;
while (size > 1){
//调整堆
adjustHeap(arr,0 ,size);
System.out.println("调整堆排序后:" + Arrays.toString(arr));
swap(arr,0,size - 1);
size -- ;
}
}
/**
* 创建大根堆,从后往前遍历所有非叶子节点(非叶子节点都有两个子节点),依次调整
*/
private void createMaxHeap(int[] arr, int size) {
for (int i= arr.length / 2 - 1 ; i >= 0 ; i --){
adjustHeap(arr,i,size);
}
}
/**
* 堆调整算法逻辑,非叶子节点和左右子节点比较,子节点大于则调整
*/
private void adjustHeap(int[] arr,int index, int size){
//左节点
int left = 2 * index + 1;
int right = 2 * index + 2;
int largest = index;
if(left < size && arr[left] > arr[largest]){
largest = left;
}
if(right < size && arr[right] > arr[largest]){
largest = right;
}
if(largest != index){
swap(arr,index,largest);
adjustHeap(arr , largest ,size);
}
}
//交换元素
private void swap(int[] arr , int i ,int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
运行代码结果详细解析:
原始数据排序:[56, 36, 78, 94, 13, 47, 32, 51, 22, -12, -89, 3, 23, 3, 94]
创建大根堆后:[94, 56, 94, 51, 13, 47, 78, 36, 22, -12, -89, 3, 23, 3, 32]
调整堆排序后:[94, 56, 78, 51, 13, 47, 32, 36, 22, -12, -89, 3, 23, 3, 94]
调整堆排序后:[78, 56, 47, 51, 13, 23, 32, 36, 22, -12, -89, 3, 3, 94, 94]
调整堆排序后:[56, 51, 47, 36, 13, 23, 32, 3, 22, -12, -89, 3, 78, 94, 94]
调整堆排序后:[51, 36, 47, 22, 13, 23, 32, 3, 3, -12, -89, 56, 78, 94, 94]
调整堆排序后:[47, 36, 32, 22, 13, 23, -89, 3, 3, -12, 51, 56, 78, 94, 94]
调整堆排序后:[36, 22, 32, 3, 13, 23, -89, -12, 3, 47, 51, 56, 78, 94, 94]
调整堆排序后:[32, 22, 23, 3, 13, 3, -89, -12, 36, 47, 51, 56, 78, 94, 94]
调整堆排序后:[23, 22, 3, 3, 13, -12, -89, 32, 36, 47, 51, 56, 78, 94, 94]
调整堆排序后:[22, 13, 3, 3, -89, -12, 23, 32, 36, 47, 51, 56, 78, 94, 94]
调整堆排序后:[13, 3, 3, -12, -89, 22, 23, 32, 36, 47, 51, 56, 78, 94, 94]
调整堆排序后:[3, -12, 3, -89, 13, 22, 23, 32, 36, 47, 51, 56, 78, 94, 94]
调整堆排序后:[3, -12, -89, 3, 13, 22, 23, 32, 36, 47, 51, 56, 78, 94, 94]
调整堆排序后:[-12, -89, 3, 3, 13, 22, 23, 32, 36, 47, 51, 56, 78, 94, 94]
最终数据排序:[-89, -12, 3, 3, 13, 22, 23, 32, 36, 47, 51, 56, 78, 94, 94]
花费时间:4毫秒
原理很简单,每次创建出新堆,堆顶为此时堆的最大值,堆顶和堆尾交换,堆长度减1,重新创建新堆,不断重复,直到堆长度为1结束,此时形成一个升序数组。