程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 堆排序算法的講授及Java版完成

堆排序算法的講授及Java版完成

編輯:關於JAVA

堆排序算法的講授及Java版完成。本站提示廣大學習愛好者:(堆排序算法的講授及Java版完成)文章只能為提供參考,不一定能成為您想要的結果。以下是堆排序算法的講授及Java版完成正文


堆是數據構造中的一種主要構造,懂得了“堆”的概念和操作,可以疾速控制堆排序。

堆的概念
堆是一種特別的完整二叉樹(complete binary tree)。假如一棵完整二叉樹的一切節點的值都不小於其子節點,稱之為年夜根堆(或年夜頂堆);一切節點的值都不年夜於其子節點,稱之為小根堆(或小頂堆)。
在數組(在0號下標存儲根節點)中,輕易獲得上面的式子(這兩個式子很主要):
1.下標為i的節點,父節點坐標為(i-1)/2;
2.下標為i的節點,左子節點坐標為2*i+1,右子節點為2*i+2。

堆的樹立和保護
堆可以支撐多種操作,但如今我們關懷的只要兩個成績:
1.給定一個無序數組,若何樹立為堆?
2.刪除堆頂元素後,若何調劑數構成為新堆?
先看第二個成績。假定我們曾經有一個現成的年夜根堆。如今我們刪除根元素,但並沒有挪動其余元素。想一想產生了甚麼:根元素空了,但其它元素還堅持著堆的性質。我們可以把最初一個元素(代號A)挪動到根元素的地位。假如不是特別情形,則堆的性質被損壞。但這僅僅是因為A小於其某個子元素。因而,我們可以把A和這個子元素更換地位。假如A年夜於其一切子元素,則堆調劑好了;不然,反復上述進程,A元素在樹形構造中赓續“下沉”,直到適合的地位,數組從新恢復堆的性質。上述進程普通稱為“挑選”,偏向明顯是自上而下。
刪除一個元素是如斯,拔出一個新元素也是如斯。分歧的是,我們把新元素放在末尾,然後和其父節點做比擬,即自下而上挑選。
那末,第一個成績怎樣處理呢?
我看過的數據構造的書許多都是從第一個非葉子結點向下挑選,直到根元素挑選終了。這個辦法叫“挑選法”,須要輪回挑選n/2個元素。
但我們還可以自創“惹是生非”的思緒。我們可以視第一個元素為一個堆,然後赓續向個中添加新元素。這個辦法叫做“拔出法”,須要輪回拔出(n-1)個元素。
因為挑選法和拔出法的方法分歧,所以,雷同的數據,它們樹立的堆普通分歧。

年夜致懂得堆以後,堆排序就是瓜熟蒂落的工作了。

算法概述/思緒
我們須要一個升序的序列,怎樣辦呢?我們可以樹立一個最小堆,然後每次輸入根元素。然則,這個辦法須要額定的空間(不然將形成年夜量的元素挪動,其龐雜度會飙升到O(n^2))。假如我們須要當場排序(即不許可有O(n)空間龐雜度),怎樣辦?
有方法。我們可以樹立最年夜堆,然後我們倒著輸入,在最初一個地位輸入最年夜值,次末地位輸入次年夜值……因為每次輸入的最年夜元素會騰出第一個空間,是以,我們正好可以放置如許的元素而不須要額定空間。很英俊的設法主意,是否是?

public class HeapSort { 
 
  public static void main(String[] args) { 
    int[] arr = { 50, 10, 90, 30, 70, 40, 80, 60, 20 }; 
    System.out.println("排序之前:"); 
    for (int i = 0; i < arr.length; i++) { 
      System.out.print(arr[i] + " "); 
    } 
 
    // 堆排序 
    heapSort(arr); 
 
    System.out.println(); 
    System.out.println("排序以後:"); 
    for (int i = 0; i < arr.length; i++) { 
      System.out.print(arr[i] + " "); 
    } 
  } 
 
  /** 
   * 堆排序 
   */ 
  private static void heapSort(int[] arr) {  
    // 將待排序的序列構建成一個年夜頂堆 
    for (int i = arr.length / 2; i >= 0; i--){  
      heapAdjust(arr, i, arr.length);  
    } 
     
    // 慢慢將每一個最年夜值的根節點與末尾元故舊換,而且再調劑二叉樹,使其成為年夜頂堆 
    for (int i = arr.length - 1; i > 0; i--) {  
      swap(arr, 0, i); // 將堆頂記載和以後未經排序子序列的最初一個記載交流 
      heapAdjust(arr, 0, i); // 交流以後,須要從新檢討堆能否相符年夜頂堆,不相符則要調劑 
    } 
  } 
 
  /** 
   * 構建堆的進程 
   * @param arr 須要排序的數組 
   * @param i 須要構建堆的根節點的序號 
   * @param n 數組的長度 
   */ 
  private static void heapAdjust(int[] arr, int i, int n) { 
    int child; 
    int father;  
    for (father = arr[i]; leftChild(i) < n; i = child) { 
      child = leftChild(i); 
       
      // 假如左子樹小於右子樹,則須要比擬右子樹和父節點 
      if (child != n - 1 && arr[child] < arr[child + 1]) { 
        child++; // 序號增1,指向右子樹 
      } 
       
      // 假如父節點小於孩子結點,則須要交流 
      if (father < arr[child]) { 
        arr[i] = arr[child]; 
      } else { 
        break; // 年夜頂堆構造未被損壞,不須要調劑 
      } 
    } 
    arr[i] = father; 
  } 
 
  // 獲得到左孩子結點 
  private static int leftChild(int i) { 
    return 2 * i + 1; 
  } 
   
  // 交流元素地位 
  private static void swap(int[] arr, int index1, int index2) { 
    int tmp = arr[index1]; 
    arr[index1] = arr[index2]; 
    arr[index2] = tmp; 
  } 
} 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved