堆排序解剖

堆排序

算法介紹

是一種數據結構,可以把堆看成一棵完全二叉樹,這棵完全二叉樹滿足:任何一個非葉結點的值都不大於(或不小於)其左右孩子結點的值。若父親大孩子小,叫大頂堆;若父親小孩子大,則這樣的堆叫做小頂堆

二叉樹:每個結點最多隻有兩棵子樹,即二叉樹中結點的度只能爲0、1、2。子樹有左右之分,不能顛倒。

滿二叉樹:在一棵二叉樹中,如果所有的分支結點都有左孩子和右孩子結點,並且葉子結點都集中在二叉樹的最下一層。另一種定義:一棵深度爲k且有個結點的二叉樹稱爲滿二叉樹。

完全二叉樹:深度爲k,有n個結點的二叉樹,當且僅當其每一個結點都與深度爲k的滿二叉樹中編號從1至n的結點一一對應時,稱之爲完全二叉樹。通俗來講,一棵完全二叉樹是由一棵滿二叉樹從右至左從下而上,挨個刪除結點所得到的。

堆排序的思想:將一個無序序列調整爲一個堆,就可以找出這個序列的最大(或最小)值,然後將找出的這個值交換到序列的最後(或最前),這樣有序序列元素增加·個,無序序列中元素減少1個,對新的無序序列重複這樣的操作,就實現了排序。

堆排序執行過程

l  將原始序列化爲一個完全二叉樹。

l  從無序序列所確定的完全二叉樹的第一個非葉子結點開始,從右至左,從下至上,對每一個結點進行調整,最終將得到一個大頂堆。

對結點的調整方法:將當前結點(假設爲a)的值與其孩子結點進行比較,如果存在大於a值的孩子結點,則從中選出最大的一個與a交換。當a來到下一層的時候重複上述過程,直到a的孩子結點值都小於a的值爲止。

l  將當前無序序列中第一個元素,反映在樹中是根節點(假設爲a)與無序序列中最後一個元素交換(假設爲b)。a進入有序序列,到達最終位置。無序序列中元素減少1個,有序序列中元素增加1個。此時只有結點b可能不滿足堆的定義,對其進行調整。

l  重複3)中的過程,知道無序序列中的元素剩下1個時排序結束

算法代碼(Java)

/**
 * 堆排序
 * @author 卡羅-晨
 *
 */
public class HeapSort {
	
	/**
	 * 找出左孩子
	 * @param i 堆下標
	 * @return 左孩子的下標
	 */
	public static int leftChild(int i) {
		return 2*i+1;
	}
	
	/**
	 * 用於刪除一個最大值和建立堆
	 * @param a 無序序列
	 * @param i 過濾下來的位置
	 * @param n 堆的邏輯大小
	 */
	private static <T extends Comparable<? super T>> void percDown(T[] a,int i,int n) {
		int child;
		T tmp;
		for (tmp = a[i];leftChild(i)<n;i=child) {
			child = leftChild(i);
			if(child != n-1 && a[child].compareTo(a[child+1])<0) {
				child++;
			}
			if(tmp.compareTo(a[child])<0) {
				a[i] = a[child];
			}else 
				break;
		}
		a[i] = tmp;
	}
	/**
	 * 標準堆排序
	 * @param a可比較的集合
	 */
	public static <T extends Comparable<? super T>> void heapsort(T[] a) {
		//建立堆
		for(int i=a.length/2-1;i>=0;i--) {
			percDown(a, i, a.length);
		}
		for(int i=a.length-1;i>0;i--) {
			T tmp = a[0];
			a[0] = a[i];
			a[i] = tmp;
			percDown(a, 0, i);
		}
	}


}


性能分析

時間複雜度

對於percDown()方法來說,顯然child走的是一條從當前結點到葉子結點的路徑,完全二叉樹的高度爲log(n+1),即對每個結點調整的時間複雜度爲O(logn)。對於heapsort()方法,基本操作總數應該是兩個並列的for循環中基本操作的次數相加,第一個循環的基本操作次數爲O(logn)*n/2,第二個循環基本操作次數爲O(logn)*(n-1),因此整個算法的基本操作次數問爲O(logn)*n/2+ O(logn)*(n-1),化簡後得其時間複雜度爲O(nlogn)

空間複雜度

從算法代碼可以看出,本算法的額外空間只有一個tmp,因此額外空間複雜度爲O(1)。

注意:堆排序的最壞情況下的時間複雜度也是O(nlogn),這是它相當於快速排序的最大優點,堆排序的空間複雜度爲O(1),在所有時間複雜度爲O(nlogn)的排序中是最小的,這也是其一大優點,堆排序適合的場景是記錄數很多的情況。

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