Java實現堆的封裝,進行插入,調整,刪除堆頂以完成堆排序實例

簡介


堆對于排序算法是一個比較常用的數據結構,下面我就使用Java語言來實現這一算法


首先,我們需要知道堆的數據結構的形式,其實就是一個特殊的二叉樹。但是這個二叉樹有一定的特點,除了是完全二叉樹以外,對于最大堆而言,堆頂元素的值是最大的,而且對于堆的每一個子樹也是一個小一號的最大堆;同樣對于最小堆,性質相反就可以了。


我以最大堆為例:
要實現堆的初始化操作,就是先按照給定的元素創建一棵完全二叉樹,然后從末尾節點進行不斷地調整的過程。調整的原則是:比較要進行放置的當前節點與其父節點的數值的大小,若要進行放置的當前節點的值小于其父節點,那么當前節點所在位置符合最大堆的定義,要進行放置的當前節點放在此處是比較合適的;如果要進行放置的當前節點的值大于其父節點的值,那說明放在當前節點是不合適的,那么就需要將當前節點的值與其父節點的值進行交換,然后原父節點變為新的要進行放置的當前節點。循環比較;終止條件就是當前節點沒有父節點,但此時的調整也許并沒有結束,我們只需要讓堆頂元素為要插入的值即可。至此,最大堆的插入和調整過程結束。
代碼如下:

public boolean insert(int x){
        if(currentSize==MAXSIZE){
            System.out.println("Sorry,this heap is full!");
            return false;
        }
        //如果堆不滿的話
        currentSize++;
        int flag=currentSize-1;
        while(flag>0){
            int parent=(flag-1)/2;
            if(heap[parent]>x){
                heap[flag]=x;
                return true;
            }else{
                heap[flag]=heap[parent];
                flag=parent;
            }
        }
        heap[0]=x;
        return true;
    }

siftDown過程:給定一個節點的位置,對其進行調整,使之符合最大堆的定義,這個過程就是我們要實現的過程。調整原則如下:
對于當前節點i而言,其孩子節點的下標滿足左節點為2i+1,右節點為2i+2;在進行調整的過程中,只需要比較當前節點與其子節點中最大的節點進行調整即可。具體的代碼邏輯可在代碼中看到:

public void siftDown(int flag){
        int want=flag;
        int x=heap[flag];
        
        while(want<currentSize){
            int lChild=2*want+1;
            int rChild=2*want+2;
            int MAXChildNumber;
            if(lChild>currentSize){  //沒有孩子節點
                heap[want]=x;
            }else{                   //有兩個孩子節點
                if(lChild<currentSize){
                    MAXChildNumber=heap[lChild]>heap[rChild]?lChild:rChild;
                }else{
                    MAXChildNumber=lChild;
                }
                if(heap[MAXChildNumber]<x){
                    heap[want]=x;return;
                }else{
                    heap[want]=heap[MAXChildNumber];
                    want=MAXChildNumber;
                }
            }
        }
        
    }

堆頂元素的刪除,我們對堆的操作基本桑就是為了獲得這個堆的最值,那么毫無疑問,堆頂元素就是我們要研究的對象。下面是代碼邏輯:

public int deleteTop(){
        if(currentSize<0){
            System.out.println("Sorry, this heap is empty!");
            return -1;
        }
        int target=heap[0];
        int substitute=heap[currentSize-1];
        this.currentSize--;
        heap[0]=substitute;
        siftDown(0);
        return target;
    }


下面是詳細的代碼

package test.maxHeap;

public class MaxHeap {
    
    private int []heap ;
    private int currentSize;
    private static int MAXSIZE ;
    
    public MaxHeap(int n){
        heap=new int[n];
        currentSize=0;
        MAXSIZE=n;
    }
    
    public boolean insert(int x){
        if(currentSize==MAXSIZE){
            System.out.println("Sorry,this heap is full!");
            return false;
        }
        //如果堆不滿的話
        currentSize++;
        int flag=currentSize-1;
        while(flag>0){
            int parent=(flag-1)/2;
            if(heap[parent]>x){
                heap[flag]=x;
                return true;
            }else{
                heap[flag]=heap[parent];
                flag=parent;
            }
        }
        heap[0]=x;
        return true;
    }
    
    public void siftDown(int flag){
        int want=flag;
        int x=heap[flag];
        
        while(want<currentSize){
            int lChild=2*want+1;
            int rChild=2*want+2;
            int MAXChildNumber;
            if(lChild>currentSize){  //沒有孩子節點
                heap[want]=x;
            }else{                   //有兩個孩子節點
                if(lChild<currentSize){
                    MAXChildNumber=heap[lChild]>heap[rChild]?lChild:rChild;
                }else{
                    MAXChildNumber=lChild;
                }
                if(heap[MAXChildNumber]<x){
                    heap[want]=x;return;
                }else{
                    heap[want]=heap[MAXChildNumber];
                    want=MAXChildNumber;
                }
            }
        }
        
    }

    public int deleteTop(){
        if(currentSize<0){
            System.out.println("Sorry, this heap is empty!");
            return -1;
        }
        int target=heap[0];
        int substitute=heap[currentSize-1];
        this.currentSize--;
        heap[0]=substitute;
        siftDown(0);
        return target;
    }

}


好了,編碼已經完成。下面我們就要檢驗一下是否正確吧。

public class MaxHeapTest {

    public static void main(String []args){
        MaxHeap maxHeap=new MaxHeap(7);
        for(int i=1;i<=7;i++){
            maxHeap.insert(i);
        }
        for(int i=0;i<7;i++){
            System.out.print(maxHeap.deleteTop()+"   ");
        }
        System.out.println("\n");
    }
}


接下來是程序的運行結果:

7   6   5   4   3   2   1   
//可見,對于最大堆,刪除堆頂的操作實際上就是完成了對堆的排序任務,也證明了我們的代碼是正確的

總結:
堆的操作很重要,我們更要學會對于堆的應用,這樣的數據結構才能使得程序的運行更加的高效和流暢。對于最小堆,我們只需要在插入方法,sift方法內稍加修改即可(也就是將值的代銷變換關系進行調整)。這樣就同樣能實現最小堆的創建和相關的操作了。
代碼中可能存在不太恰當地地方,希望大家予以批評指正,期待與你們共同進步!

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

推薦閱讀更多精彩內容