Java 堆排序

      n 個元素的序列A[1].key,A[2].key,…,A[n].key,當且僅當滿足下述關係時,稱之爲堆。

      大根堆            小根堆   

      將其看成二叉樹,則大根堆所有的父節點都不小於它的子節點,小根堆所有的父節點都不大於它的子節點,以大根堆爲例。

      第一步,建堆:調整無序序列,使其滿足大根堆的定義;

      第二步,篩選:輸出堆頂元素,即將堆頂元素和當前無序序列的最後一個元素交換位置,調整剩餘元素使其成爲一個新的堆,新堆元素個數減1;

      第三步,繼續執行第二步,直到排序完成。

      建堆是一個自下而上的調整過程,由最後一個非終端節點開始進行調整,然後依次向上調整二叉樹,使其最終滿足大根堆;調整是從上往下的過程,使不滿足大根堆定義的二叉樹交換父節點和子節點的位置,使其最終滿足大根堆的定義。

      核心代碼如下: 

/* 建堆 */
for (int i=n/2; i>0; --i) {
	heapAdjust(array, i, n);           // 由最後一個非終端節點開始進行自下而上的調整
}
System.out.println("初次建堆完成的序列:");
print(array);
/* 篩選 */
for (int i=1; i<n; ++i) {
	array[0] =array[1];               // 輸出堆頂元素
	array[1] = array[n-i+1];
	array[n-i+1] = array[0];
	heapAdjust(array, 1, n-i);        // 調整堆
}
System.out.println("堆排序完成的序列:");
print(array);
/* 調整 */
heapAdjust(int[] arr, int s, int length) { // arr[s]不滿足堆的定義,length爲數組arr的長度
	int temp;
	for (int i=2*s; i<=length; i*=2) {                           // 循環是爲了使以s節點爲根結點的二叉樹滿足堆的定義
		if (i<length && arr[i]<arr[i+1]) {
			++i;                                            // 令i指向關鍵字較大記錄
		}
		if (arr[i/2] >= arr[i])  
                        break;		                                // >=成立,說明調整完畢
		temp = arr[i];                                          // 否則使其和關鍵字較大的記錄交換位置
		arr[i] = arr[i/2];
		arr[i/2] = temp;
	}
}

運行結果:

                 

注:(1)堆排序是不穩定的排序。

        (2)時間複雜度爲O(nlog2n),最壞情況下時間複雜度爲O(nlog2n)的算法。

        (3)空間複雜度爲O(1)。





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