簡單排序算法實現——堆排序

堆排序 (Heap Sort) 是利用了數據結構:完全二叉樹來進行排序的算法。其基本原理先要將完全二叉樹以數組的形式實現出來。再者,用於堆排序的完全二叉樹必須滿足最大堆(Max Heap) 的性質,即任意一個非葉子節點上的值都應該比其左孩子和右孩子的值小,滿足該性質的即稱爲最大堆。

先闡述在數組上實現完全二叉樹的原理:

對於數組下標從0開始的java語言,對於給定的節點下標 i ,其父節點下標爲 (i-1)/2, 左孩子節點下標爲 2*i+1, 右孩子的節點下標爲 2*(i+1).

另外,一個重要的結論是,最後一個非葉子節點的下標是a.length/2-1, 從a.length/2開始後面的下標對應的都是葉子節點,沒有孩子。


堆排序的實現需要三個操作。

第一個是最大堆調整操作 (MAX_HEAPIFY) , 接收參數 a[i], i 將以 i 爲根節點的子樹做調整,使得子節點永遠小於父節點,從而滿足最大堆性質。

第二個操作是創建最大堆操作 (BUILD_MAX_HEAP),將待排序數組中的元素排列成最大堆的數組實現。調用時,從最後一個非葉子節點的下標a.length/2-1開始向前遍歷使用最大堆調整操作。

第三個操作是堆排序操作 (HeapSortOnMaxHeap),每次移除整個堆的根節點 (即當前的最大元素),然後進行堆調整的遞歸運算。

爲了實現原地排序,加入指標heapSize,與a.length區別開來,在堆排序操作中,移除最大元素的操作實現爲將第一個元素交換到數組的最後,然後heapSize減一,表明該元素已經不在堆中了。


下面給出全部的java代碼實現,其中加了一個公共類的HeapSort作爲驅動,依次調用創建最大堆操作和堆排序操作,同時加入了計算父親/孩子節點對應下標的輔助方法。

public class HeapSort{
	private static int heapSize;
	
	
	private static int indexOfLeft(int root){
		return (2*root+1); 
	}
	
	private static int indexOfRight(int root){
		return 2*(root+1);
	}
	
	private static int indexOfParent(int root){
		return (root-1)/2;
	}
	
	//This method will examine node at position i and its two childs.
	//If i is smaller than one of its child, it will adjust it to maintain it as 
	//a max heap
	private static <AnyType extends Comparable<? super AnyType>>
	void MAX_HEAPIFY(AnyType[] a, int i){
		int l=indexOfLeft(i);
		int r=indexOfRight(i);
		int indexOfMax;
		
		//Condition l,r<=heapSize ensures that operation on leaf nodes will be tolerated.
		if(l<=heapSize-1&&a[l].compareTo(a[i])>0) indexOfMax=l;
		else indexOfMax=i; //If max==a[i], no operation at last;
		
		if(r<=heapSize-1&&a[r].compareTo(a[indexOfMax])>0)
			indexOfMax=r;
		
		if(indexOfMax!=i){
			AnyType temp=a[i];
			a[i]=a[indexOfMax];
			a[indexOfMax]=temp;
			
			MAX_HEAPIFY(a, indexOfMax);	
		}
		
	}
	
	private static <AnyType extends Comparable<? super AnyType>>
	void BUILD_MAX_HEAP(AnyType[] a){
		heapSize=a.length;
		for(int i=a.length/2-1;i>=0;i--){
			MAX_HEAPIFY(a,i);
		}
	}
	
	private static <AnyType extends Comparable<? super AnyType>>
	void HeapSortOnMaxHeap(AnyType[] a){
		AnyType temp;
		for(int i=a.length-1;i>=1;i--){
			temp=a[0];
			a[0]=a[i];
			a[i]=temp;
			
			heapSize--;
			
			MAX_HEAPIFY(a,0);
		}
	}
	
	public static <AnyType extends Comparable<? super AnyType>>
	void HeapSort(AnyType[] a){
		BUILD_MAX_HEAP(a);
		HeapSortOnMaxHeap(a);
		
	}
	
	public static void main(String[] args){
		System.out.println("Heap Sort:");
		
		Integer[] elements={3,4,1,8,10,2,0,6,5};
		
		System.out.print("Original elements: ");
		for(int i=0;i<elements.length;i++) System.out.print(elements[i]+" ");
		System.out.println();
		
		HeapSort(elements);
		
		System.out.print("After sorting: ");
		for(int i=0;i<elements.length;i++) System.out.print(elements[i]+" ");
		System.out.println();
	}

}


堆排序的平均時間複雜度爲O(nlogn), 該複雜度同時也爲最優時間複雜度。


附圖一張:


至今基本排序算法的實現練習暫時告一段落,這些排序算法的一些高級優化或特性,以及其他高級排序算法,留待以後再做研究。

接下來開始一些基本數據結構的實現練習。

發佈了30 篇原創文章 · 獲贊 9 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章