1. 程式人生 > >數據結構——堆排序(使用Java)

數據結構——堆排序(使用Java)

空間 nlog closed pso 算法 隨機數組 復雜度 sed 記錄

一、簡介

  堆排序(HeapSort)是選擇排序的改進版,它可以減少在選擇排序中的比較次數,進而減少排序時間,堆排序法用到了二叉樹的技巧,它利用堆積樹來完成,堆積是一種特殊的二叉樹,可分為大根堆和小根堆。

  大根堆需要具備的條件:

它是一棵完全二叉樹

所有節點的值都大於或等於它左右子節點的值

樹根是堆積數中最大的

小根堆需要具備的條件:  

它是一棵完全二叉樹

所有節點的值都小於或等於它左右子節點的值

樹根是堆積數中最小的

二、核心思想

  利用大根堆(小根堆)堆頂記錄的是最大關鍵字(最小關鍵字)這一特性,使得每次從無序中選擇最大記錄(最小記錄)變得簡單。

其基本思想為(大根堆):

1)將初始待排序關鍵字序列(R1,R2....Rn)構建成大根堆,此堆為初始的無須區;

2)將堆頂元素R[1]與最後一個元素R[n]交換,此時得到新的無序區(R1,R2,......Rn-1)和新的有序區(Rn),且滿足R[1,2...n-1]<=R[n];

3)由於交換後新的堆頂R[1]可能違反堆的性質,因此需要對當前無序區(R1,R2,......Rn-1)調整為新堆,然後再次將R[1]與無序區最後一個元素交換,得到新的無序區(R1,R2....Rn-2)和新的有序區(Rn-1,Rn)。不斷重復此過程直到有序區的元素個數為n-1,則整個排序過程完成。

操作過程如下:

1)初始化堆:將R[1..n]構造為堆;

2)將當前無序區的堆頂元素R[1]同該區間的最後一個記錄交換,然後將新的無序區調整為新的堆。

因此對於堆排序,最重要的兩個操作就是構造初始堆和調整堆,其實構造初始堆事實上也是調整堆的過程,只不過構造初始堆是對所有的非葉節點都進行調整。

三、圖例說明

建立初始堆:

技術分享

然後,交換堆頂的元素和最後一個元素,此時最後一個位置作為有序區(有序區顯示為黃色),然後進行其他無序區的堆調整,重新得到大頂堆後,交換堆頂和倒數第二個元素的位置……

技術分享

  重復此過程,直至得到有序序列

  技術分享

四、代碼實現

技術分享
 1 private static
void heapSort(int[] a) { 2 int n=a.length;//獲取數組長度 3 int temp;//用於交換數據 4 //構建出初始堆 5 for (int i = n/2; i >=0; i--) { 6 addDatetoHeap(a,i,n-1); 7 } 8 System.out.println(); 9 System.out.print("原始堆:"); 10 for (int i = 0; i < a.length; i++) { 11 System.out.print(a[i]+" "); 12 } 13 System.out.println(); 14 for (int i = n-2; i>=0; i--) { 15 //將樹根排到有序序列中,然後繼續構建堆 16 temp=a[i+1]; 17 a[i+1]=a[0]; 18 a[0]=temp; 19 addDatetoHeap(a, 0, i); 20 } 21 } 22 23 private static void addDatetoHeap(int[] a, int i, int n) { 24 25 int temp=a[i];//記錄父節點 26 int post=0;//用於判斷父節點是否比子節點達 27 int j=2*i;//記錄子節點 28 while(j<=n&&post==0){ 29 if(j<n){ 30 if (a[j]<a[j+1]) {//尋找最大節點 31 j++; 32 } 33 } 34 if(temp>=a[j]){//如果樹根較大就結束比較過程 35 post=1; 36 }else { 37 a[j/2]=a[j];//樹根較小,繼續比較 38 j=2*j; 39 } 40 a[j/2]=temp; 41 } 42 } 43 public static void main(String[] args) { 44 int[]a=new int[10]; 45 Random ran=new Random(); 46 System.out.println("排序前數組"); 47 //使用Random方法生成一個隨機數組並輸出 48 for (int i = 0; i < a.length; i++) { 49 a[i]=ran.nextInt(100); 50 System.out.print(a[i]+" "); 51 } 52 //調用排序方法 53 heapSort(a); 54 //輸出排序後方法 55 System.out.println("排序後數組"); 56 for (int i = 0; i < a.length; i++) { 57 58 System.out.print(a[i]+" "); 59 } 60 }
View Code

五、算法分析

  1. 所有情況下時間復雜度均為O(nlogn)。
  2. 堆排序是不穩定排序法。
  3. 只需一個額外的空間,空間復雜都為O(1).

數據結構——堆排序(使用Java)