十九、自己動手實現排序算法(7)-------- “ Heap Sort 堆排序 ”

參考文章:

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);
		
	}
	
}

 

 

堆排序代碼測試:

代碼一:

 

 

代碼二:

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章