堆排序是利用堆這種數據結構而設計的一種排序算法,堆排序是一種選擇排序,它的最壞,最好,平均時間複雜度均爲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);
}
}*/
}
參考思路:堆排序