堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序。首先简单了解下堆结构。
堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。如下图:
同时,我们对堆中的结点按层进行编号,将这种逻辑结构映射到数组中就是下面这个样子
该数组从逻辑上讲就是一个堆结构,我们用简单的公式来描述一下堆的定义就是:
大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]
小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]
堆排序基本思想及步骤
堆排序的基本思想是:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了。
示例代码:
package Sort;
import java.util.Arrays;
/**
* @Auther: wj
* @Date: 2020/2/6
* @Description: 最大堆排序
* @version: 1.0
*/
public class HeapSort {
public static void main(String[] args){
int[] arr={2,1,7,9,5,4};
for(int i=0;i<arr.length;i++){
maxHeapify(arr,arr.length-i);//arr.length-i 表示每次最大值存贮在数组最后一位
//由于是最大堆排序,每次全数组排序后,最大值都在arr[0]
int temp=arr[0];
arr[0]=arr[arr.length-i-1];
arr[arr.length-i-1]=temp;
}
System.out.println(Arrays.toString(arr));
}
/**
* 一次全数组的堆排序
* @param arr 待排序数组
* @param size 数组大小
*/
public static void maxHeapify(int[] arr,int size){
for(int i=size-1;i>=0;i--){
Heapify(arr,i,size);
}
}
/**
* 堆排序(父与子之间)
* @param arr 待排序数组
* @param root 根节点
* @param size 数组大小
*/
public static void Heapify(int[] arr,int root,int size){
int left=2*root+1;//左孩子
int right=2*root+2;//右孩子
int max=root;//假设最大值为根节点
if(left<size){
if(arr[left]>=arr[max]){
max=left;
}
}
if(right<size){
if(arr[right]>=arr[max]){
max=right;
}
}
//最大值不是根元素,就交换
if(root!=max){
int temp=arr[root];
arr[root]=arr[max];
arr[max]=temp;
}
//叶子节点,直接返回上一层
if(root==max) return;
//当前父子节点比较完成,继续比较
Heapify(arr, max, size);
}
/* public static void main(String[] args) {
int[] arr={2,1,8,9,5,4};
//每次彻底堆排序后,最大元素在前,排除一个元素size-1
for(int i=0;i<arr.length;i++){
maxHeapify(arr,arr.length-i);
//彻底一次排序后,最大值arr[0]与最后元素进行交换
int temp=arr[0];
arr[0]=arr[(arr.length-1)-i];
arr[(arr.length-1)-i]=temp;
}
System.out.println(Arrays.toString(arr));
}
*//**
* 一次彻底的堆排序,可以找出当前数组最大值
* @param arr 排序数组
* @param size 需要排序数组大小
*//*
public static void maxHeapify(int[] arr,int size){
for(int i=size-1;i>=0;i--){
heapify(arr,i,size);
}
}
*//**
* 堆排序(一次父与子)
* @param arr 排序数组
* @param root 当前父节点
* @param size 数组大小(判断是否还存在子节点)
*//*
public static void heapify(int[] arr,int root,int size){
//如果当前父节点存在
if(root<size){
int left=2*root+1;//左孩子
int right=2*root+2;//右孩子
//默认当前节点为最大值
int max=root;
if(left<size){
if(arr[left]>=arr[max]){
max=left;
}
}
if(right<size){
if(arr[right]>=arr[max]){
max=right;
}
}
//最大值不是根元素,就交换
if(max!=root){
int temp=arr[root];
arr[root]=arr[max];
arr[max]=temp;
}
// 只存在当前节点。没有叶子节点存在-->结束递归条件
if(max==root) return;
//当前父子节点比较完成,完成下一次比较
heapify(arr, max, size);
}
}*/
}
参考思路:堆排序