Java實現---堆排序 Heap Sort


堆排序快速排序歸並排序一樣都是時間復雜度為O(N*logN)的幾種常見排序方法。學習堆排序前,先講解下什么是數據結構中的二叉堆。

堆的定義

  n個元素的序列{k1,k2,…,kn}當且僅當滿足下列關系之一時,稱之為堆。

  情形1:k<= k2i 且k<= k2i+1 最小化堆小頂堆

  情形2:k>= k2i 且k>= k2i+1 (化堆大頂堆

  其中i=1,2,…,n/2向下取整;

若將和此序列對應的一維數組(即以一維數組作此序列的存儲結構)看成是一個完全二叉樹,則堆的含義表明,完全二叉樹中所有非終端結點的值均不大於(或不小於)其左、右孩子結點的值。

  由此,若序列{k1,k2,…,kn}是堆,則堆頂元素(或完全二叉樹的根)必為序列中n個元素的最小值(或最大值)。

堆的存儲

  一般用數組來表示堆,若根結點存在序號0處, i結點的父結點下標就為(i-1)/2。i結點的左右子結點下標分別為2*i+1和2*i+2。

     

堆排序的實現

  實現堆排序需要解決兩個問題:

    1.如何由一個無序序列建成一個堆?

    2.如何在輸出堆頂元素之后,調整剩余元素成為一個新的堆?

  先考慮第二個問題,一般在輸出堆頂元素之后,視為將這個元素排除,然后用表中最后一個元素填補它的位置,自上向下進行調整:首先將堆頂元素和它的左右子樹的根結點進行比較,把最小的元素交換到堆頂;然后順着被破壞的路徑一路調整下去,直至葉子結點,就得到新的堆。

  我們稱這個自堆頂至葉子的調整過程為“篩選”。

  從無序序列建立堆的過程就是一個反復“篩選”的過程。

示例代碼:

package heapSort;

/**
 * 堆排序,采用順序存儲
 * 大根堆
 * @author 超超boy
 *
 */
public class HeapSort2 {
	int[] arr;
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		HeapSort2 heapSor = new HeapSort2();
		int[] arr = {7,23,45,9,40,73,12,49};  //0下標放的是數組長度,
	    heapSor.arr = arr;
		heapSor.heapSort(arr);
		
		for(int i=0;i<arr.length;i++)
			System.out.print(".."+arr[i]);
	}
	void heapAdjust(int[] arr,int s,int m){
		//已知arr[s...m]中記錄的關鍵字除arr[s]之外均滿足堆的定義,本函數調整arr[s]的關鍵字,使arr[s...m]成為一個最大堆
		int rc = arr[s]; //s是最后一個非葉子節點
		
		for(int j=2*s;j <= m;j = s*2){
			if(j<m && arr[j]<arr[j+1])
				j++;  //j為key較大的下標
			if(rc >= arr[j]) break;
		     arr[s] = arr[j];  //上移到父節點
		     s=j;
		}
		arr[s]=rc;  //要放入的位置
		
	}
	
	void heapSort(int[] arr){
		//對數組進行建堆操作,就是從最后一個非葉結點進行篩選的過程
		for(int i=(arr.length-1)/2;i > 0;i--){//因為0沒有使用,所以length-1
			heapAdjust(arr,i,arr.length-1);  
		}
		System.out.println("........建堆完成.............");
		
		outputArr(1);
		for(int i=arr.length-1; i>1; i--){
			int temp = arr[1];
			arr[1] = arr[i];
			arr[i] = temp;
			heapAdjust(arr,1,i-1);
		}
	}
	void outputArr(int i){
		
		if(i <= arr[0]){
			System.out.println(arr[i]);
			outputArr(i*2);  //左
			outputArr(i*2+1);  //右
		}
	}
}

  運行結果:

.....................
73
45
40
23
49
12
9
..7..9..12..23..40..45..49..73

堆排序分析

     堆排序方法對記錄數較少的文件並不值得提倡,但對n較大的文件還是很有效的。因為其運行時間主要耗費在建初始堆和調整建新堆時進行的反復“篩選”上。

  堆排序在最壞的情況下,其時間復雜度也為O(nlogn)。相對於快速排序來說,這是堆排序的最大優點。此外,堆排序僅需一個記錄大小的供交換用的輔助存儲空間。

 轉發請注明出處:http://www.cnblogs.com/jycboy/p/5689728.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM