參考文章:
https://www.cnblogs.com/guoyaohua/p/8600214.html 十大經典排序算法最強總結(含JAVA代碼實現)
https://mp.weixin.qq.com/s/3krwgrzB6EV4HU7wI0Rm4A 堆排序就這麼簡單
堆排序分析:
平均時間複雜度 | 最好情況 | 最壞情況 | 空間複雜度 | 排序方式 | 穩定性 |
O(n*logn) | O(n*log n) | O(n*log n) | O(1) | In-place | 不穩定 |
堆排序原理:
堆排序(Heapsort)是指利用堆這種數據結構所設計的一種排序算法。堆積是一個近似完全二叉樹的結構,並同時滿足堆積的性質:即子結點的鍵值或索引總是小於(或者大於)它的父節點。
溫馨提示:算法描述,排序原理搞不懂,先把最大(小)堆搞明白了,然後再看這篇文章。
堆排序算法描述:
- 將初始待排序關鍵字序列(R1,R2….Rn)構建成大頂堆,此堆爲初始的無序區;
- 將堆頂元素R[1]與最後一個元素R[n]交換,此時得到新的無序區(R1,R2,……Rn-1)和新的有序區(Rn),且滿足R[1,2…n-1]<=R[n];
- 由於交換後新的堆頂R[1]可能違反堆的性質,因此需要對當前無序區(R1,R2,……Rn-1)調整爲新堆,然後再次將R[1]與無序區最後一個元素交換,得到新的無序區(R1,R2….Rn-2)和新的有序區(Rn-1,Rn)。不斷重複此過程直到有序區的元素個數爲n-1,則整個排序過程完成。
堆排序原理圖解:
Java 代碼實現:
代碼一:
package com.sorting.algorithm;
public class HeapSort {
public static int[] heapSort(int[] array){
int n = array.length;
// 把數組堆化 heapify, 創建最大堆
for (int i = (n-1-1)/2; i >= 0; i--) {
siftDown(array,n,i);
}
// 將創建好的最大堆最大值放到數組最後,並重建除最大值以外的數組,建立最大堆,循環或遞歸進行
for (int i = n-1; i > 0; i--) {
swap(array,0,i);
siftDown(array,i,0);
}
return array;
}
private static void swap(int[] array, int i, int j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
// 堆中原始的下沉操作
private static void siftDown2(int[] array, int n, int k) {
while(2*k+1 < n){
// j 代表左右子樹最大值的下標
int j = 2*k +1;
if(j+1 < n && array[j] < array[j+1])
j++;
// 如果父節點 大於 左右子樹節點就跳出循環
if(array[j] < array[k]) break;
// 將父節點和左右子樹中的最大值交換位置
swap(array, k, j);
// 迭代看子樹是否需要下沉操作
k=j;
}
}
// 堆中改進的下沉操作
private static void siftDown(int[] array, int n, int k) {
int e = array[k];
while(2*k+1 < n){
int j = 2*k +1;
if(j+1 < n && array[j] < array[j+1])
j++;
if(array[j] < array[k]) break;
array[k] = array[j];
k=j;
}
array[k] = e;
}
public static void printArr(int[] array){
for (int i = 0; i < array.length; i++) {
if(i != array.length-1)
System.out.print(array[i] + ",");
else
System.out.println(array[i]);
}
}
public static void main(String[] args) {
int[] array = { 58,36,70,22,88,64,1,32 };
System.out.println("排序之前:");
printArr(array);
System.out.println("-------------------------------");
System.out.println("排序過程");
heapSort(array);
System.out.println("-------------------------------");
System.out.println("排序之後:");
printArr(array);
}
}
代碼二:
package com.sorting.algorithm;
public class HeapSort2 {
// 用來記錄變化的數組長度
private static int len;
public static int[] heapSort(int[] array){
len = array.length;
// 將數組堆化
buildMaxHeap(array);
// 將最大堆中的最大值放大數組的後面,數組長度減一,並重建最大堆 ,循環遍歷,知道完成排序
while(len > 0){
printArr(array);
swap(array,0,len-1);
len--;
printArr(array);
adjustHeap(array,0);
}
return array;
}
// 調整最大堆,使它符合最大堆的性質
private static void adjustHeap(int[] array, int i) {
int maxIndex = i;
if(2*i <len && array[maxIndex] < array[2*i])
maxIndex = 2*i;
if(2*i+1 <len && array[maxIndex] < array[2*i+1])
maxIndex = 2*i+1;
// 遞歸調用 adjustHeap ,讓父節點,左右子樹都符合最大堆的性質
if(maxIndex != i){
swap(array, i, maxIndex);
adjustHeap(array, maxIndex);
}
}
private static void swap(int[] array, int i, int j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
// 將數組堆化
private static void buildMaxHeap(int[] array) {
int n = array.length;
for(int i = n/2; i >= 0; i--){
adjustHeap(array,i);
}
}
public static void printArr(int[] array){
for (int i = 0; i < array.length; i++) {
if(i != array.length-1)
System.out.print(array[i] + ",");
else
System.out.println(array[i]);
}
}
public static void main(String[] args) {
int[] array = { 58,36,70,22,88,64,1,32 };
System.out.println("排序之前:");
printArr(array);
System.out.println("-------------------------------");
System.out.println("排序過程");
heapSort(array);
System.out.println("-------------------------------");
System.out.println("排序之後:");
printArr(array);
}
}
堆排序代碼測試:
代碼一:
代碼二: