堆排序算法-OC實現(xiàn)

  • 簡介

堆排序(英語:Heapsort)是指利用堆這種數(shù)據(jù)結(jié)構(gòu)所設(shè)計的一種排序算法癌淮。堆是一個近似完全二叉樹的結(jié)構(gòu),并同時滿足堆積的性質(zhì):即子結(jié)點的鍵值或索引總是小于(或者大于)它的父節(jié)點繁仁。
堆分為最大堆和最小堆,其實就是完全二叉樹。最大堆要求節(jié)點的元素都要不小于其孩子采够,最小堆要求節(jié)點元素都不大于其左右孩子,兩者對左右孩子的大小關(guān)系不做任何要求冰垄,其實很好理解蹬癌。有了上面的定義,我們可以得知虹茶,處于最大堆的根節(jié)點的元素一定是這個堆中的最大值逝薪。

  • 算法原理

1、將初始待排序關(guān)鍵字序列(R1,R2....Rn)構(gòu)建成大頂堆蝴罪,此堆為初始的無序區(qū)
2董济、將堆頂元素R[1]與最后一個元素R[n]交換,此時得到新的無序區(qū)(R1,R2,......Rn-1)和新的有序區(qū)(Rn)
3要门、由于交換后新的堆頂R[1]可能違反堆的性質(zhì)虏肾,因此需要對當前無序區(qū)(R1,R2,......Rn-1)調(diào)整為新堆,然后再次將R[1]與無序區(qū)最后一個元素交換欢搜,得到新的無序區(qū)(R1,R2....Rn-2)和新的有序區(qū)(Rn-1,Rn)封豪。不斷重復此過程直到有序區(qū)的元素個數(shù)為n-1,則整個排序過程完成

  • C語言實現(xiàn)
//最大堆調(diào)整(Max Heapify):將堆的末端子節(jié)點作調(diào)整炒瘟,使得子節(jié)點永遠小于父節(jié)點
void maxHeapify(int numbers[], int start, int end) {
    //建立父節(jié)點指標和子節(jié)點指標
    int dad = start;
    int son = dad * 2 + 1;
    while (son <= end) { //若子節(jié)點指標在范圍內(nèi)才做比較
        if (son + 1 <= end && numbers[son] < numbers[son + 1]) { //先比較兩個子節(jié)點大小吹埠,選擇最大的
            son++;
        }
        if (numbers[dad] > numbers[son]) {//如果父節(jié)點大于子節(jié)點代表調(diào)整完畢,直接跳出函數(shù)
            return;
        }else { //否則交換父子內(nèi)容再繼續(xù)子節(jié)點和孫節(jié)點比較
            int temp = numbers[son];
            numbers[son] = numbers[dad];
            numbers[dad] = temp;
            dad = son;
            son = dad * 2 + 1;
        }
    }
}

/**堆排序(HeapSort):
 1疮装、首先從最后一個父節(jié)點做最大堆調(diào)整缘琅,找出最大值,此時最大值位于根節(jié)點
 2廓推、然后將最大值和已排好元素(依次找出的最大值排出的序列刷袍,如:6 3 9 23 12 8 [15 16 17 18])前一位元素交換位置,再將除已排好元素外的其他元素(6 3 9 23 12 8)做最大堆調(diào)整樊展,找出最大值做个,此時最大值位于根節(jié)點
 3、重復步驟2滚局,直至結(jié)束
 */
void heapSort(int numbers[], int length) {
    //初始化居暖,i從最後一個父節(jié)點開始做最大堆調(diào)整,調(diào)整結(jié)束后根節(jié)點得到最大值
    for (int i = length / 2 - 1; i >= 0; i--) {
        maxHeapify(numbers, i, length - 1);
    }
    //先將第一個元素和已排好元素前一位做交換,再重新調(diào)整藤肢,直到排序完畢
    for (int i = length - 1; i > 0; i--) {
        int temp = numbers[0];
        numbers[0] = numbers[i];
        numbers[i] = temp;
        maxHeapify(numbers, 0, i - 1);
    }
}

//調(diào)用
    int number[5] = {95, 45, 15, 78, 84};
    heapSort(number, 5);
    for (i = 0; i < 5; i++) {
        printf("%d\n", number[i]);
    }
  • OC實現(xiàn)
//最大堆調(diào)整(Max Heapify):將堆的末端子節(jié)點作調(diào)整太闺,使得子節(jié)點永遠小于父節(jié)點
- (void)maxHeapifyWithNumbers:(NSMutableArray *)numbers start:(int)start end:(int)end {
    //建立父節(jié)點指標和子節(jié)點指標
    int dad = start;
    int son = dad * 2 + 1;
    while (son <= end) { //若子節(jié)點指標在范圍內(nèi)才做比較
        if (son + 1 <= end && [numbers[son] intValue] < [numbers[son + 1] intValue]) { //先比較兩個子節(jié)點大小,選擇最大的
            son++;
        }
        if ([numbers[dad] intValue] > [numbers[son] intValue]) {//如果父節(jié)點大于子節(jié)點代表調(diào)整完畢嘁圈,直接跳出函數(shù)
            return;
        }else { //否則交換父子內(nèi)容再繼續(xù)子節(jié)點和孫節(jié)點比較
            [numbers exchangeObjectAtIndex:son withObjectAtIndex:dad];
            dad = son;
            son = dad * 2 + 1;
        }
    }
}

/**堆排序(HeapSort):
 1省骂、首先從最后一個父節(jié)點做最大堆調(diào)整蟀淮,找出最大值,此時最大值位于根節(jié)點
 2钞澳、然后將最大值和已排好元素(依次找出的最大值排出的序列怠惶,如:6 3 9 23 12 8 [15 16 17 18])前一位元素交換位置,再將除已排好元素外的其他元素(6 3 9 23 12 8)做最大堆調(diào)整轧粟,找出最大值策治,此時最大值位于根節(jié)點
 3、重復步驟2兰吟,直至結(jié)束
 */
- (void)heapSortWithNumbers:(NSMutableArray *)numbers {
    //初始化通惫,i從最後一個父節(jié)點開始做最大堆調(diào)整,調(diào)整結(jié)束后根節(jié)點得到最大值
    for (int i = (int)numbers.count / 2 - 1; i >= 0; i--) {
        [self maxHeapifyWithNumbers:numbers start:i end:(int)numbers.count - 1];
    }
    //先將第一個元素和已排好元素前一位做交換,再重新調(diào)整混蔼,直到排序完畢
    for (int i = (int)numbers.count - 1; i > 0; i--) {
        [numbers exchangeObjectAtIndex:0 withObjectAtIndex:i];
        [self maxHeapifyWithNumbers:numbers start:0 end:i - 1];
    }
    NSLog(@"%@",numbers);
}

//調(diào)用
NSMutableArray *array = [NSMutableArray arrayWithObjects:@(10),@(4),@(8),@(99),@(16),@(19),@(3), nil];
[self heapSortWithNumbers:array];
  • 時間復雜度

最好履腋、最壞和平均時間復雜度都為O(nlogn)。

  • 算法穩(wěn)定性

不穩(wěn)定的排序算法

提供一個他人的更詳細的解讀堆排序

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末惭嚣,一起剝皮案震驚了整個濱河市遵湖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌晚吞,老刑警劉巖奄侠,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異载矿,居然都是意外死亡,警方通過查閱死者的電腦和手機烹卒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門闷盔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人旅急,你說我怎么就攤上這事逢勾。” “怎么了藐吮?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵溺拱,是天一觀的道長。 經(jīng)常有香客問我谣辞,道長迫摔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任泥从,我火速辦了婚禮句占,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘躯嫉。我一直安慰自己纱烘,他們只是感情好杨拐,可當我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著擂啥,像睡著了一般哄陶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上哺壶,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天屋吨,我揣著相機與錄音,去河邊找鬼变骡。 笑死离赫,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的塌碌。 我是一名探鬼主播渊胸,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼台妆!你這毒婦竟也來了翎猛?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤接剩,失蹤者是張志新(化名)和其女友劉穎切厘,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體懊缺,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡疫稿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了鹃两。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片遗座。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖俊扳,靈堂內(nèi)的尸體忽然破棺而出途蒋,到底是詐尸還是另有隱情,我是刑警寧澤馋记,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布号坡,位于F島的核電站,受9級特大地震影響梯醒,放射性物質(zhì)發(fā)生泄漏宽堆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一茸习、第九天 我趴在偏房一處隱蔽的房頂上張望日麸。 院中可真熱鬧,春花似錦、人聲如沸代箭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽嗡综。三九已至乙帮,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間极景,已是汗流浹背察净。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留盼樟,地道東北人氢卡。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像晨缴,于是被迫代替她去往敵國和親译秦。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,086評論 2 355

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