最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

堆排序算法的講解及Java版實(shí)現(xiàn)

 更新時(shí)間:2016年05月04日 17:44:29   作者:飛翔的貓咪  
這篇文章主要介紹了堆排序算法的講解及Java版實(shí)現(xiàn),堆排序基于堆這種數(shù)據(jù)結(jié)構(gòu),在本文中對(duì)堆的概念也有補(bǔ)充介紹,需要的朋友可以參考下

堆是數(shù)據(jù)結(jié)構(gòu)中的一種重要結(jié)構(gòu),了解了“堆”的概念和操作,可以快速掌握堆排序。

堆的概念
堆是一種特殊的完全二叉樹(shù)(complete binary tree)。如果一棵完全二叉樹(shù)的所有節(jié)點(diǎn)的值都不小于其子節(jié)點(diǎn),稱之為大根堆(或大頂堆);所有節(jié)點(diǎn)的值都不大于其子節(jié)點(diǎn),稱之為小根堆(或小頂堆)。
在數(shù)組(在0號(hào)下標(biāo)存儲(chǔ)根節(jié)點(diǎn))中,容易得到下面的式子(這兩個(gè)式子很重要):
1.下標(biāo)為i的節(jié)點(diǎn),父節(jié)點(diǎn)坐標(biāo)為(i-1)/2;
2.下標(biāo)為i的節(jié)點(diǎn),左子節(jié)點(diǎn)坐標(biāo)為2*i+1,右子節(jié)點(diǎn)為2*i+2。

堆的建立和維護(hù)
堆可以支持多種操作,但現(xiàn)在我們關(guān)心的只有兩個(gè)問(wèn)題:
1.給定一個(gè)無(wú)序數(shù)組,如何建立為堆?
2.刪除堆頂元素后,如何調(diào)整數(shù)組成為新堆?
先看第二個(gè)問(wèn)題。假定我們已經(jīng)有一個(gè)現(xiàn)成的大根堆。現(xiàn)在我們刪除了根元素,但并沒(méi)有移動(dòng)別的元素。想想發(fā)生了什么:根元素空了,但其它元素還保持著堆的性質(zhì)。我們可以把最后一個(gè)元素(代號(hào)A)移動(dòng)到根元素的位置。如果不是特殊情況,則堆的性質(zhì)被破壞。但這僅僅是由于A小于其某個(gè)子元素。于是,我們可以把A和這個(gè)子元素調(diào)換位置。如果A大于其所有子元素,則堆調(diào)整好了;否則,重復(fù)上述過(guò)程,A元素在樹(shù)形結(jié)構(gòu)中不斷“下沉”,直到合適的位置,數(shù)組重新恢復(fù)堆的性質(zhì)。上述過(guò)程一般稱為“篩選”,方向顯然是自上而下。
刪除一個(gè)元素是如此,插入一個(gè)新元素也是如此。不同的是,我們把新元素放在末尾,然后和其父節(jié)點(diǎn)做比較,即自下而上篩選。
那么,第一個(gè)問(wèn)題怎么解決呢?
我看過(guò)的數(shù)據(jù)結(jié)構(gòu)的書(shū)很多都是從第一個(gè)非葉子結(jié)點(diǎn)向下篩選,直到根元素篩選完畢。這個(gè)方法叫“篩選法”,需要循環(huán)篩選n/2個(gè)元素。
但我們還可以借鑒“無(wú)中生有”的思路。我們可以視第一個(gè)元素為一個(gè)堆,然后不斷向其中添加新元素。這個(gè)方法叫做“插入法”,需要循環(huán)插入(n-1)個(gè)元素。
由于篩選法和插入法的方式不同,所以,相同的數(shù)據(jù),它們建立的堆一般不同。

大致了解堆之后,堆排序就是水到渠成的事情了。

算法概述/思路
我們需要一個(gè)升序的序列,怎么辦呢?我們可以建立一個(gè)最小堆,然后每次輸出根元素。但是,這個(gè)方法需要額外的空間(否則將造成大量的元素移動(dòng),其復(fù)雜度會(huì)飆升到O(n^2))。如果我們需要就地排序(即不允許有O(n)空間復(fù)雜度),怎么辦?
有辦法。我們可以建立最大堆,然后我們倒著輸出,在最后一個(gè)位置輸出最大值,次末位置輸出次大值……由于每次輸出的最大元素會(huì)騰出第一個(gè)空間,因此,我們恰好可以放置這樣的元素而不需要額外空間。很漂亮的想法,是不是?

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) {  
    // 將待排序的序列構(gòu)建成一個(gè)大頂堆 
    for (int i = arr.length / 2; i >= 0; i--){  
      heapAdjust(arr, i, arr.length);  
    } 
     
    // 逐步將每個(gè)最大值的根節(jié)點(diǎn)與末尾元素交換,并且再調(diào)整二叉樹(shù),使其成為大頂堆 
    for (int i = arr.length - 1; i > 0; i--) {  
      swap(arr, 0, i); // 將堆頂記錄和當(dāng)前未經(jīng)排序子序列的最后一個(gè)記錄交換 
      heapAdjust(arr, 0, i); // 交換之后,需要重新檢查堆是否符合大頂堆,不符合則要調(diào)整 
    } 
  } 
 
  /** 
   * 構(gòu)建堆的過(guò)程 
   * @param arr 需要排序的數(shù)組 
   * @param i 需要構(gòu)建堆的根節(jié)點(diǎn)的序號(hào) 
   * @param n 數(shù)組的長(zhǎng)度 
   */ 
  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); 
       
      // 如果左子樹(shù)小于右子樹(shù),則需要比較右子樹(shù)和父節(jié)點(diǎn) 
      if (child != n - 1 && arr[child] < arr[child + 1]) { 
        child++; // 序號(hào)增1,指向右子樹(shù) 
      } 
       
      // 如果父節(jié)點(diǎn)小于孩子結(jié)點(diǎn),則需要交換 
      if (father < arr[child]) { 
        arr[i] = arr[child]; 
      } else { 
        break; // 大頂堆結(jié)構(gòu)未被破壞,不需要調(diào)整 
      } 
    } 
    arr[i] = father; 
  } 
 
  // 獲取到左孩子結(jié)點(diǎn) 
  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; 
  } 
} 

相關(guān)文章

  • 解決springboot中自定義JavaBean返回的json對(duì)象屬性名稱大寫(xiě)變小寫(xiě)問(wèn)題

    解決springboot中自定義JavaBean返回的json對(duì)象屬性名稱大寫(xiě)變小寫(xiě)問(wèn)題

    開(kāi)發(fā)過(guò)程中發(fā)現(xiàn)查詢返回的數(shù)據(jù)出現(xiàn)自定義的JavaBean的屬性值大小寫(xiě)格式出現(xiàn)問(wèn)題,導(dǎo)致前端無(wú)法接受到數(shù)據(jù),目前有四種解決方法,根據(jù)大佬的經(jīng)驗(yàn)之談,前兩種是最簡(jiǎn)單便捷的,后兩種是比較通用的方法,需要的朋友可以參考下
    2023-10-10
  • Java遍歷Map對(duì)象集合的六種方式代碼示例

    Java遍歷Map對(duì)象集合的六種方式代碼示例

    Java中的Map是一種鍵值對(duì)映射的數(shù)據(jù)結(jié)構(gòu),它提供了一些常用的方法用于獲取、添加、刪除和修改元素,下面這篇文章主要給大家介紹了關(guān)于Java遍歷Map對(duì)象集合的六種方式,需要的朋友可以參考下
    2024-02-02
  • JDBC獲取元數(shù)據(jù)demo

    JDBC獲取元數(shù)據(jù)demo

    這篇文章主要為大家介紹了JDBC獲取元數(shù)據(jù)實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • mybatis批量update時(shí)報(bào)錯(cuò)multi-statement not allow的問(wèn)題

    mybatis批量update時(shí)報(bào)錯(cuò)multi-statement not allow的問(wèn)題

    這篇文章主要介紹了mybatis批量update時(shí)報(bào)錯(cuò)multi-statement not allow的問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • 一個(gè)例子帶你看懂Java中synchronized關(guān)鍵字到底怎么用

    一個(gè)例子帶你看懂Java中synchronized關(guān)鍵字到底怎么用

    synchronized是Java里的一個(gè)關(guān)鍵字,起到的一個(gè)效果是"監(jiān)視器鎖",它的功能就是保證操作的原子性,同時(shí)禁止指令重排序和保證內(nèi)存的可見(jiàn)性,下面這篇文章主要給大家介紹了關(guān)于如何通過(guò)一個(gè)例子帶你看懂Java中synchronized關(guān)鍵字到底怎么用的相關(guān)資料,需要的朋友可以參考下
    2022-10-10
  • Java面試問(wèn)題知識(shí)點(diǎn)總結(jié)

    Java面試問(wèn)題知識(shí)點(diǎn)總結(jié)

    本文主要介紹并且整理了Java面試知識(shí)點(diǎn)總結(jié),,有需要的小伙伴可以參考下
    2017-04-04
  • java提取json中某個(gè)數(shù)組的所有值方法

    java提取json中某個(gè)數(shù)組的所有值方法

    下面小編就為大家分享一篇java提取json中某個(gè)數(shù)組的所有值方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-03-03
  • 圖文詳解Java中的序列化機(jī)制

    圖文詳解Java中的序列化機(jī)制

    java中的序列化可能大家像我一樣都停留在實(shí)現(xiàn)Serializable接口上,對(duì)于它里面的一些核心機(jī)制沒(méi)有深入了解過(guò)。本文將通過(guò)示例帶大家深入了解Java中的序列化機(jī)制,需要的可以參考一下
    2022-10-10
  • 淺談Sharding-JDBC強(qiáng)制路由案例實(shí)戰(zhàn)

    淺談Sharding-JDBC強(qiáng)制路由案例實(shí)戰(zhàn)

    本文主要介紹了淺談Sharding-JDBC強(qiáng)制路由案例實(shí)戰(zhàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • Java?Timer使用講解

    Java?Timer使用講解

    Timer是一種工具,線程用其安排以后在后臺(tái)線程中執(zhí)行的任務(wù)??砂才湃蝿?wù)執(zhí)行一次,或者定期重復(fù)執(zhí)行,這篇文章主要介紹了Java?Timer使用講解,需要的朋友可以參考下
    2022-11-11

最新評(píng)論

当阳市| 郑州市| 揭西县| 双峰县| 安泽县| 尖扎县| 广南县| 内黄县| 蒙城县| 正镶白旗| 马公市| 亚东县| 岳池县| 二手房| 滨州市| 独山县| 长春市| 兴宁市| 沈阳市| 云梦县| 苍溪县| 昭觉县| 昂仁县| 家居| 临洮县| 柳河县| 哈巴河县| 内乡县| 穆棱市| 洱源县| 泗洪县| 青海省| 浮梁县| 青田县| 拜泉县| 宝兴县| 延津县| 航空| 连南| 乐平市| 江油市|