堆排序

堆的定義

    n個元素的序列{k1,k2祝钢,…, kn} 當(dāng)且僅當(dāng)滿足下列關(guān)系之一時,稱之為堆催跪。
  情形1:ki <= k2i 且ki <= k2i+1(**最小化堆**或**小頂堆**)
  情形2:ki>= k2i且ki>= k2i+1(**最****大****化堆**或**大頂堆**)
  其中i=1,2,…,n/2向下取整;

概念

若將和此序列對應(yīng)的一維數(shù)組(即以一維數(shù)組作此序列的存儲結(jié)構(gòu))看成是一個完全二叉樹,則堆的含義表明夷野,完全二叉樹中所有非終端結(jié)點的值均不大于(或不小于)其左懊蒸、右孩子結(jié)點的值。
  由此悯搔,若序列{k1骑丸,k2,…,kn}是堆妒貌,則堆頂元素(或完全二叉樹的根)必為序列中n個元素的最小值(或最大值)通危。
  例如,下列兩個序列為堆灌曙,對應(yīng)的完全二叉樹如圖:

圖片.png

堆排序:若在輸出堆頂?shù)淖钚≈抵缶盏沟檬S鄋-1個元素的序列重又建成一個堆,則得到n個元素的次小值在刺。如此反復(fù)執(zhí)行逆害,便能得到一個有序序列,這個過程稱之為堆排序蚣驼。

堆的存儲

一般用數(shù)組來表示堆魄幕,若根結(jié)點存在序號0處, i結(jié)點的父結(jié)點下標(biāo)就為(i-1)/2颖杏。i結(jié)點的左右子結(jié)點下標(biāo)分別為2i+1和2i+2纯陨。
  (注:如果根結(jié)點是從1開始输玷,則左右孩子結(jié)點分別是2i和2i+1队丝。)
  如第0個結(jié)點左右子結(jié)點下標(biāo)分別為1和2。
  如最大化堆如下:
  

左圖為其存儲結(jié)構(gòu)欲鹏,右圖為其邏輯結(jié)構(gòu)机久。

堆排序的實現(xiàn)

在輸出堆頂元素之后,視為將這個元素排除赔嚎,然后用表中最后一個元素填補(bǔ)它的位置膘盖,自上向下進(jìn)行調(diào)整:首先將堆頂元素和它的左右子樹的根結(jié)點進(jìn)行比較,把最小的元素交換到堆頂尤误;然后順著被破壞的路徑一路調(diào)整下去侠畔,直至葉子結(jié)點,就得到新的堆损晤。
我們稱這個自堆頂至葉子的調(diào)整過程為“篩選”软棺。
從無序序列建立堆的過程就是一個反復(fù)“篩選”的過程。

構(gòu)造初始堆

初始化堆的時候是對所有的非葉子結(jié)點進(jìn)行篩選尤勋。
最后一個非終端元素的下標(biāo)是[n/2]向下取整喘落,所以篩選只需要從第[n/2]向下取整個元素開始茵宪,從后往前進(jìn)行調(diào)整。
比如瘦棋,給定一個數(shù)組稀火,首先根據(jù)該數(shù)組元素構(gòu)造一個完全二叉樹。
然后從最后一個非葉子結(jié)點開始赌朋,每次都是從父結(jié)點凰狞、左孩子、右孩子中進(jìn)行比較交換沛慢,交換可能會引起孩子結(jié)點不滿足堆的性質(zhì)赡若,所以每次交換之后需要重新對被交換的孩子結(jié)點進(jìn)行調(diào)整。

進(jìn)行堆排序

有了初始堆之后就可以進(jìn)行排序了颠焦。
堆排序是一種選擇排序斩熊。建立的初始堆為初始的無序區(qū)。
排序開始伐庭,首先輸出堆頂元素(因為它是最值)粉渠,將堆頂元素和最后一個元素交換,這樣圾另,第n個位置(即最后一個位置)作為有序區(qū)霸株,前n-1個位置仍是無序區(qū),對無序區(qū)進(jìn)行調(diào)整集乔,得到堆之后去件,再交換堆頂和最后一個元素,這樣有序區(qū)長度變?yōu)?扰路。尤溜。。
不斷進(jìn)行此操作汗唱,將剩下的元素重新調(diào)整為堆宫莱,然后輸出堆頂元素到有序區(qū)。每次交換都導(dǎo)致無序區(qū)-1哩罪,有序區(qū)+1授霸。不斷重復(fù)此過程直到有序區(qū)長度增長為n-1,排序完成际插。

堆排序?qū)嵗?/h3>

首先碘耳,建立初始的堆結(jié)構(gòu)如圖:
  



  然后,交換堆頂?shù)脑睾妥詈笠粋€元素框弛,此時最后一個位置作為有序區(qū)(有序區(qū)顯示為黃色)辛辨,然后進(jìn)行其他無序區(qū)的堆調(diào)整,重新得到大頂堆后,交換堆頂和倒數(shù)第二個元素的位置……
  



  重復(fù)此過程:
  

最后愉阎,有序區(qū)擴(kuò)展完成即排序完成:
  


由排序過程可見绞蹦,若想得到升序力奋,則建立大頂堆榜旦,若想得到降序,則建立小頂堆景殷。
代碼
  假設(shè)排列的元素為整型溅呢,且元素的關(guān)鍵字為其本身。
  因為要進(jìn)行升序排列猿挚,所以用大頂堆咐旧。
  根結(jié)點從0開始,所以i結(jié)點的左右孩子結(jié)點的下標(biāo)為2i+1和2i+2绩蜻。

算法描述

//堆賽選函數(shù)
//已知H[start-end]中除了start之外均滿足堆的定義
//本函數(shù)進(jìn)行調(diào)整铣墨,使H[start-end]成為一個大頂堆
typedef int ElemType;
void HeapAdjust(ElemType H[], int start, int end) {
    ElemType temp = H[start];
    for (int i = 2 * start + 1; i <= end; i *= 2) {
        //因為根節(jié)點的序號為0 而不是1  所以i結(jié)點左孩子和右孩子分別為2i+1和2i+2
        if (i < end && H[i] < H[i + 1]) {
            //左右孩子進(jìn)行比較
            ++i;//i為較大記錄的下標(biāo)
        }
        if (temp > H[i]) {
            //左右孩子中獲勝者與父親的比較
            break;
        }
        //將孩子結(jié)點上位,則以孩子結(jié)點的位置進(jìn)行下一輪的賽選
        H[start] = H[i];
        start = i;
    }
    H[start] = temp;//插入最開始不和諧的元素
}

void HeapSort(ElemType A[], int n) {
    //先建立大頂堆
    for (int i = n/2; i >= 0; --i) {
        HeapAdjust(A, i, n);
    }
    //進(jìn)行排序
    for (int i = n - 1; i > 0; --i) {
        //最后一個元素和第一個元素進(jìn)行比較
        ElemType temp = A[i];
        A[i] = A[0];
        A[0] = temp;
        //然后將剩下的無序元素繼續(xù)調(diào)整為大頂堆
        HeapAdjust(A, 0, i - 1);
    }
}

int main() {
    int a[] = {9, 1, 2, 5, 7, 4, 8, 6, 3, 5};
    int len = sizeof(a)/sizeof(int);
    HeapSort(a, len);
    for (int i = 0; i < len; i++) {
        printf("%d\n", a[i]);
    }
    return 0;
}

算法穩(wěn)定性

不穩(wěn)定

算法分析

時間復(fù)雜度: O(nlogn)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末办绝,一起剝皮案震驚了整個濱河市伊约,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌孕蝉,老刑警劉巖屡律,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異降淮,居然都是意外死亡超埋,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進(jìn)店門佳鳖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來霍殴,“玉大人,你說我怎么就攤上這事系吩±赐ィ” “怎么了?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵淑玫,是天一觀的道長巾腕。 經(jīng)常有香客問我,道長絮蒿,這世上最難降的妖魔是什么尊搬? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮土涝,結(jié)果婚禮上佛寿,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好冀泻,可當(dāng)我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布常侣。 她就那樣靜靜地躺著,像睡著了一般弹渔。 火紅的嫁衣襯著肌膚如雪胳施。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天肢专,我揣著相機(jī)與錄音舞肆,去河邊找鬼。 笑死博杖,一個胖子當(dāng)著我的面吹牛椿胯,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播剃根,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼哩盲,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了狈醉?” 一聲冷哼從身側(cè)響起廉油,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎舔糖,沒想到半個月后娱两,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡金吗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年十兢,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片摇庙。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡旱物,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出卫袒,到底是詐尸還是另有隱情宵呛,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布夕凝,位于F島的核電站宝穗,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏码秉。R本人自食惡果不足惜逮矛,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望转砖。 院中可真熱鬧须鼎,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至赡译,卻和暖如春仲吏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背捶朵。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工蜘矢, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人综看。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像岖食,于是被迫代替她去往敵國和親红碑。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容

  • 堆排序 堆排序是利用堆這種數(shù)據(jù)結(jié)構(gòu)而設(shè)計的一種排序算法泡垃,堆排序是一種選擇排序析珊,它的最壞,最好蔑穴,平均時間復(fù)雜度均為O...
    尼小摩閱讀 11,773評論 3 11
  • 選擇排序 每次在n個記錄中選擇一個最小的需要比較n-1次忠寻,但是這樣的操作并沒有把每一趟的比較結(jié)果保存下來,在后一趟...
    wlj1107閱讀 1,700評論 0 2
  • 本文的目標(biāo)是要做出優(yōu)先隊列和堆排序兩個Demo存和。 完全二叉樹 優(yōu)先隊列 堆排序 完全二叉樹 完全二叉樹的定義是建立...
    囧書閱讀 4,947評論 13 48
  • tangjq@haisum.com
    芔翕閱讀 169評論 0 0
  • 1 我不想牽著你的手奕剃,心里想著她。 ——《春嬌與志明》 認(rèn)識一個朋友捐腿,相貌平平纵朋,但為人熱情開朗,每每相聚茄袖,她響亮而...
    花田夜語閱讀 700評論 0 2