PHP算法系列教程(三)-堆排序

PHP算法系列教程(三)-堆排序

介紹

要介紹堆排序我們就要先了解什么是堆.

什么是堆

堆(二叉堆)可以視為一棵完全的二叉樹(shù),完全二叉樹(shù)的一個(gè)性質(zhì)是除了最底層之外古胆,每一層都是滿的喊儡,這使得堆可以利用數(shù)組來(lái)表示
完全二叉樹(shù)有一下幾個(gè)特點(diǎn)

  1. parent(i) = floor(i/2)愚臀,i 的父節(jié)點(diǎn)下標(biāo)
  2. left(i) = 2i科雳,i 的左子節(jié)點(diǎn)下標(biāo)
  3. right(i) = 2i + 1,i 的右子節(jié)點(diǎn)下標(biāo)

二叉堆一般分為兩種:最大堆和最小堆,這也是我們堆排序要使用的堆.
最大堆:

  1. 最大堆中的最大元素值出現(xiàn)在根結(jié)點(diǎn)(堆頂)
  2. 堆中每個(gè)父節(jié)點(diǎn)的元素值都大于等于其孩子結(jié)點(diǎn)(如果存在)

最小堆反之.

堆排序原理

堆排序就是把最大堆堆頂?shù)淖畲髷?shù)取出蕾域,將剩余的堆繼續(xù)調(diào)整為最大堆敦间,再次將堆頂?shù)淖畲髷?shù)取出,這個(gè)過(guò)程持續(xù)到剩余數(shù)只有一個(gè)時(shí)結(jié)束.
基本操作如下:

  1. 最大堆調(diào)整: 將堆的末端子節(jié)點(diǎn)作調(diào)整束铭,使得子節(jié)點(diǎn)永遠(yuǎn)小于父節(jié)點(diǎn)
  2. 最大堆構(gòu)造: 將堆所有數(shù)據(jù)重新排序廓块,使其成為最大堆
  3. 堆排序: 移除位在第一個(gè)數(shù)據(jù)的根節(jié)點(diǎn),并做最大堆調(diào)整的遞歸運(yùn)算

代碼示例

Talk is cheap, show you my code!


/**
 * 堆排序
 * 取出最大數(shù)
 * @param $arr
 * @return mixed
 */
function heapSort($arr)
{
    buildHeap($arr);
    $length = count($arr);
    while ($length > 1) { // 長(zhǎng)度大于一才需要排序
        swap($arr, $length - 1, 0); // 將堆頂放到數(shù)組尾部(完成一次排序(取出一個(gè)最大數(shù)))
        $length --;
        adjustHeap($arr, $length, 0);
    }
    return $arr;
}

/**
 * 創(chuàng)建一個(gè)大頂堆
 * @param $arr
 */
function buildHeap(&$arr)
{
    $node = floor(count($arr) / 2) - 1 ; // 取得最后非葉子節(jié)點(diǎn)(數(shù)組0為開(kāi)始故減1)
    for ($i = $node; $i >= 0; $i--) {
        adjustHeap($arr, count($arr), $i);
    }
}

/**
 * 調(diào)整堆
 * @param $arr
 * @param $length
 * @param $node
 */
function  adjustHeap(&$arr, $length, $node)
{
    list($lchild, $rchild) = getChildNode($node);
    $max = $node; // 將改節(jié)點(diǎn)設(shè)為節(jié)點(diǎn)子樹(shù)最大節(jié)點(diǎn)
    while ($lchild < $length || $rchild < $length) { // 左右子節(jié)點(diǎn)是否存在
        if ($lchild < $length && $arr[$lchild] > $arr[$max]) { // 左節(jié)點(diǎn)大于父節(jié)點(diǎn)
            $max = $lchild;
        }
        if ($rchild < $length && $arr[$rchild] > $arr[$max]) { // 右節(jié)點(diǎn)大于父節(jié)點(diǎn)
            $max = $rchild;
        }
        if ($max != $node) { // 父節(jié)點(diǎn)是否是最大節(jié)點(diǎn)
            swap($arr, $max, $node); // 若不是交換最大節(jié)點(diǎn)和父節(jié)點(diǎn)
            $node = $max; // 當(dāng)前節(jié)點(diǎn)被最大節(jié)點(diǎn)替換,查出最大節(jié)點(diǎn)兩個(gè)子節(jié)點(diǎn)
            list($lchild, $rchild) = getChildNode($node);
        } else {
            break;
        }

    }
}


function swap(&$arr, $a, $b)
{
    list($arr[$a], $arr[$b]) = [$arr[$b], $arr[$a]];
}

/**
 * 獲取左右子節(jié)點(diǎn)
 * @param $node
 * @return array
 */
function getChildNode($node)
{
    return [$node * 2 + 1, $node * 2 + 2];
}

$arr = [21, 212, 32, 43, 12, 2, 8, 10, 3];

var_dump(heapSort($arr))

結(jié)論

堆排序時(shí)間復(fù)雜度為O(nlgn), 空間復(fù)雜度只用到數(shù)組O(1);

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末契沫,一起剝皮案震驚了整個(gè)濱河市带猴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌懈万,老刑警劉巖拴清,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異会通,居然都是意外死亡口予,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)涕侈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)沪停,“玉大人,你說(shuō)我怎么就攤上這事裳涛∧菊牛” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵端三,是天一觀的道長(zhǎng)舷礼。 經(jīng)常有香客問(wèn)我,道長(zhǎng)郊闯,這世上最難降的妖魔是什么妻献? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任蛛株,我火速辦了婚禮,結(jié)果婚禮上育拨,老公的妹妹穿的比我還像新娘谨履。我一直安慰自己,他們只是感情好至朗,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布屉符。 她就那樣靜靜地躺著剧浸,像睡著了一般锹引。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上唆香,一...
    開(kāi)封第一講書(shū)人閱讀 51,688評(píng)論 1 305
  • 那天嫌变,我揣著相機(jī)與錄音,去河邊找鬼躬它。 笑死腾啥,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的冯吓。 我是一名探鬼主播倘待,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼组贺!你這毒婦竟也來(lái)了凸舵?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤失尖,失蹤者是張志新(化名)和其女友劉穎啊奄,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體掀潮,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡菇夸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了仪吧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片庄新。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖薯鼠,靈堂內(nèi)的尸體忽然破棺而出摄咆,到底是詐尸還是另有隱情,我是刑警寧澤人断,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布吭从,位于F島的核電站,受9級(jí)特大地震影響恶迈,放射性物質(zhì)發(fā)生泄漏涩金。R本人自食惡果不足惜谱醇,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望步做。 院中可真熱鬧副渴,春花似錦、人聲如沸全度。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)将鸵。三九已至勉盅,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間顶掉,已是汗流浹背草娜。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留痒筒,地道東北人宰闰。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像簿透,于是被迫代替她去往敵國(guó)和親移袍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

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

  • 課程介紹 先修課:概率統(tǒng)計(jì)老充,程序設(shè)計(jì)實(shí)習(xí)葡盗,集合論與圖論 后續(xù)課:算法分析與設(shè)計(jì),編譯原理蚂维,操作系統(tǒng)戳粒,數(shù)據(jù)庫(kù)概論,人...
    ShellyWhen閱讀 2,290評(píng)論 0 3
  • 概述:排序有內(nèi)部排序和外部排序虫啥,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序蔚约,而外部排序是因排序的數(shù)據(jù)很大,一次不能容納全部...
    每天刷兩次牙閱讀 3,732評(píng)論 0 15
  • 概述 排序有內(nèi)部排序和外部排序涂籽,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序苹祟,而外部排序是因排序的數(shù)據(jù)很大,一次不能容納全部...
    蟻前閱讀 5,186評(píng)論 0 52
  • 關(guān)于最大堆 什么是最大堆和最小堆砂轻?最大(小)堆是指在樹(shù)中斤吐,存在一個(gè)結(jié)點(diǎn)而且該結(jié)點(diǎn)有兒子結(jié)點(diǎn)搔涝,該結(jié)點(diǎn)的data域值都...
    凌云壯志幾多愁閱讀 88,086評(píng)論 33 71
  • 666
    g5m6閱讀 280評(píng)論 0 0