堆排序

堆排序

1.前提知識

堆:(英語:heap)是計算機科學中一類特殊的數據結構的統稱。堆通常是一個可以被看做一棵樹的數組對象。

  • 堆中某個節點的值總是不大于或不小于其父節點的值;

  • 堆總是一棵完全二叉樹。

將根節點最大的堆叫做最大堆或大根堆,根節點最小的堆叫做最小堆或小根堆。

優先隊列(priority queue)

普通的隊列是一種先進先出的數據結構,元素在隊列尾追加,而從隊列頭刪除。在優先隊列中,元素被賦予優先級。當訪問元素時,具有最高優先級的元素最先刪除。優先隊列具有最高級先出 (first in, largest out)的行為特征。通常采用堆數據結構來實現。

a.完全二叉樹

若設二叉樹的深度為h,除第 h 層外,其它各層 (1~h-1) 的結點數都達到最大個數,第 h 層所有的結點都連續集中在最左邊,這就是完全二叉樹。

完全二叉樹是由滿二叉樹(一個二叉樹,如果每一個層的結點數都達到最大值,則這個二叉樹就是滿二叉樹。也就是說,如果一個二叉樹的層數為K,且結點總數是(2^k) -1 ,則它就是滿二叉樹。)而引出來的。對于深度為K的,有n個結點的二叉樹,當且僅當其每一個結點都與深度為K的滿二叉樹中編號從1至n的結點一一對應時稱之為完全二叉樹。

(1)所有的葉結點都出現在第k層或k-l層(層次最大的兩層)

(2)對任一結點,如果其右子樹的最大層次為L,則其左子樹的最大層次為L或L+l。

一棵二叉樹至多只有最下面的兩層上的結點的度數可以小于2,并且最下層上的結點都集中在該層最左邊的若干位置上,則此二叉樹成為完全二叉樹,并且最下層上的結點都集中在該層最左邊的若干位置上,而在最后一層上,右邊的若干結點缺失的二叉樹,則此二叉樹成為完全二叉樹。

b.小根堆和大根堆

假設有一棵完全二叉樹,在滿足作為完全二叉樹的基礎上,對于任意一個擁有父節點的子節點,其數值均不小于父節點的值;這樣層層遞推,就是根節點的值最小,這樣的樹,稱為小根堆。

同理,又有一棵完全二叉樹,對于任意一個子節點來說,均不大于其父節點的值,如此遞推,就是根節點的值是最大的,這樣的數,稱為大根堆。

2.一些規律

最后一個非葉節點的位置為nums.length-1,所有擁有左右子節點的節點與子節點的位置關系為,假設子節點的編號為n,那么左子節點的編號為2n+1右節點的編號為2(n+1)

然后具體的做法為1.先建立大(小)頂堆,2.交換堆頂的位置和調整整個堆,每調整一次堆的長度就減少一,直到堆的大小為0或1結束

3.先實現大頂堆

public static void main(String[] args) {
        int[] array = new int[]{1,3,4,2,5};
        heapsort(array);

其結構就相當于


image.png

然后我們先實現大頂堆

  private static int[] heapsort(int[] array) {
        buildBigheap(array);
    }

從最后一個非葉節點的節點開始調整,一直調整到根節點,這樣大頂堆就建立好了

private static void buildBigheap(int[] array) {
        for(int i=array.length/2-1;i>-1;i--){ //從最后一個非葉節點的節點開始調整,一直調整到根節點
            adjustheap(array,i,array.length);  
        }

然后是具體的調整過程:

private static void adjustheap(int[] array, int i,int end) {
        //如果沒有左右子樹或者左右子樹現在已經是拍好序的順序
        if(2*i+1 >=end){
            return;
        }else if(2*(i+1)>=end){
            if(array[2*i+1]>=array[i]){
                swap(array,2*i+1,i);
            }
        }else{
            //根已為最大
            if(array[i]>=array[2*i+1]&&array[i]>=array[2*(i+1)]){
                return;
                //左子樹最大,交換后去排列左邊
            }else if(array[2*i+1]>=array[i]&&array[2*i+1]>=array[2*(i+1)]){
                swap(array,2*i+1,i);
                adjustheap(array,2*i+1,end);
                //右子樹最大,交換后去排列右邊
            }else{
                swap(array,2*(i+1),i);
                adjustheap(array,2*(i+1),end);
            }
        }
    }

**具體就是先判斷現在調整的位置,
i(位置) \begin{cases} A.如果現在所在的節點已經沒有子節點,那么直接返回\\ B.如果現在只有一個左子節點,那么與根節點直接比較后返回\\ C.雙子節點都在,那么就分為3種情況 \end{cases}
A狀況說明(分成兩種情況:1.該節點是葉節點,2,該節點往后的子節點已經被拍好序了)
B狀況說明(因為當一個節點只含有左子節點可以用的時候,那么他的右節點一定是空或者已經排好序了)
C狀況說明(如果根最大什么都不用做,直接返回,如果左子節點最大,那么與根交換,并對左子節點的剩余節點進行調整,同理可得右子節點)
OK
現在做完這一步我們可以看一下數組結構

image.png

image.png

這個時候的根是最大的也就是已經實現了大頂堆

4.交換堆頂元素與最后一個元素,實現排序

其實這一過程就是交換調整,每一次交換都會使堆的需排序的大小減一,那么很容易就想到當堆大小為1時,調整完畢,所以用一個for循環for i array.length ->1

 for(int i =array.length-1;i>0;i--){
            swap(array,i,0);  //交換棧頂元素與堆的最后一個數據(每次最后一個數據都會減一)
            adjustheap(array,0,i);  //調整堆為大頂堆
        }

例如第一次交換后的數據為


image.png

然后調整完的數據為:


image.png

這樣做完后所有的序都已經排好了

完整代碼

public static void main(String[] args) {
        int[] array = new int[]{1,3,4,2,5};
        heapsort(array);
        for(int i=0;i<array.length;i++){
            System.out.printf(array[i]+" ");
        }
    }

    private static int[] heapsort(int[] array) {
        buildBigheap(array);
        return array;
    }

    private static void buildBigheap(int[] array) {
        for(int i=array.length/2-1;i>-1;i--){
            adjustheap(array,i,array.length);
        }

        for(int i =array.length-1;i>0;i--){
            swap(array,i,0);
            adjustheap(array,0,i);
        }
    }
    private static void adjustheap(int[] array, int i,int end) {
        //如果沒有左右子樹或者左右子樹現在已經是拍好序的順序
        if(2*i+1 >=end){
            return;
        }else if(2*(i+1)>=end){
            if(array[2*i+1]>=array[i]){
                swap(array,2*i+1,i);
            }
        }else{
            //根已為最大
            if(array[i]>=array[2*i+1]&&array[i]>=array[2*(i+1)]){
                return;
                //左子樹最大,交換后去排列左邊
            }else if(array[2*i+1]>=array[i]&&array[2*i+1]>=array[2*(i+1)]){
                swap(array,2*i+1,i);
                adjustheap(array,2*i+1,end);
                //右子樹最大,交換后去排列右邊
            }else{
                swap(array,2*(i+1),i);
                adjustheap(array,2*(i+1),end);
            }
        }
    }

    private static void swap(int[] array, int i, int j) {
        int temp = array[i];
        array[i] =array[j];
        array[j] = temp;
    }
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,491評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,263評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,708評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,409評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,939評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,774評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,650評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容

  • 關于最大堆 什么是最大堆和最小堆?最大(小)堆是指在樹中,存在一個結點而且該結點有兒子結點,該結點的data域值都...
    凌云壯志幾多愁閱讀 88,211評論 33 71
  • 二叉樹 滿二叉樹 國內教程定義:一個二叉樹,如果每一個層的結點數都達到最大值,則這個二叉樹就是滿二叉樹。也就是說,...
    簡_愛SimpleLove閱讀 4,291評論 0 3
  • 本文的目標是要做出優先隊列和堆排序兩個Demo。 完全二叉樹 優先隊列 堆排序 完全二叉樹 完全二叉樹的定義是建立...
    囧書閱讀 4,977評論 13 48
  • 一些概念 數據結構就是研究數據的邏輯結構和物理結構以及它們之間相互關系,并對這種結構定義相應的運算,而且確保經過這...
    Winterfell_Z閱讀 5,882評論 0 13
  • 堆排序可以做什么 首先應該弄清楚堆排序可以解決什么問題,答案是顯而易見的:排序。說得通俗點兒就是對一組無序的數字進...
    Springlord888閱讀 30,384評論 11 52