算法導(dǎo)論學(xué)習(xí)001-堆排序

堆排序

堆排序基本簡(jiǎn)介

1991年的計(jì)算機(jī)先驅(qū)獎(jiǎng)獲得者存捺、斯坦福大學(xué)計(jì)算機(jī)科學(xué)系教授羅伯特·弗洛伊德(Robert W.Floyd)和威廉姆斯(J.Williams)在1964年共同發(fā)明了著名的堆排序算法旅挤。

堆排序?qū)儆诒容^排序中的一種链快,具有O(nLgn)的時(shí)間復(fù)雜度栖秕,空間復(fù)雜度為O(1)弧岳。因此堆排序具有空間原址性唬涧,即任何時(shí)候都只需要常數(shù)個(gè)額外的元素空間存儲(chǔ)臨時(shí)數(shù)據(jù)。堆排序利用一種我們稱為“堆”的數(shù)據(jù)結(jié)構(gòu)來(lái)進(jìn)行排序宫补,因此在了解堆排序之前我們需要對(duì)堆這種數(shù)據(jù)結(jié)構(gòu)有個(gè)了解檬姥,才能對(duì)堆排序是如何利用該數(shù)據(jù)結(jié)果完成對(duì)數(shù)據(jù)的排序的。

堆的定義

堆是一個(gè)數(shù)組粉怕,它可以被看成是一個(gè)近似的完全二叉樹健民,樹上的每一個(gè)節(jié)點(diǎn)對(duì)應(yīng)數(shù)組中的一個(gè)元素。除了最底層外斋荞,該樹是完全充滿的荞雏,而且是從左向右填充虐秦。

堆的一些特性:

堆實(shí)際上是一棵完全二叉樹平酿,根據(jù)完全二叉樹的一些特性我們可以得到父子節(jié)點(diǎn)之間的位置關(guān)系:對(duì)于給定的一個(gè)下標(biāo)為i的節(jié)點(diǎn)我們可以很容計(jì)算到它的父節(jié)點(diǎn)下標(biāo)為i/2 左孩子下標(biāo)為2i,右孩子節(jié)點(diǎn)為2i+1(以上是在下標(biāo)為1開始計(jì)算的,對(duì)于數(shù)組從0開始的計(jì)算作簡(jiǎn)單調(diào)整即可)

最大堆 最小堆

在堆排序中我們把一個(gè)無(wú)序的序列變?yōu)橛行虻倪^程使用的并不是一棵隨意建立的二叉堆悦陋,對(duì)于升序和降序排列分別用到了最大堆以及最小堆蜈彼。因此我們需要了解一下最大堆以及最小堆相對(duì)于普通二叉堆有什么特殊特性:
對(duì)于最大堆中 除了根節(jié)點(diǎn)以外的所有子節(jié)點(diǎn)i都要滿足
A[Parent(i)]>=A[i]
這個(gè)定義表明父節(jié)點(diǎn)的值是不小于其任意的一個(gè)子節(jié)點(diǎn)的值。 因此根節(jié)點(diǎn)存儲(chǔ)的是序列的最大值俺驶,并且任一子樹中幸逆,該子樹所包含的的所有節(jié)點(diǎn)的值都不大于該子樹根節(jié)點(diǎn)的值棍辕。
對(duì)于最小堆則剛好與最大堆相反這里就不在介紹。
了解了最大堆和最小堆我們來(lái)看看堆排序的排序過程还绘。(以下我們利用最大堆來(lái)進(jìn)行排序)

堆排序的過程

  • BUILD-MAX-HEAP
  • MAX-HEAPIPY
  • HEAP-SORT

堆排序由以上三個(gè)步驟分別是建立最大堆楚昭,最大堆維護(hù) 堆排序。

由于BUILD-MAX-HEAP實(shí)際是通過循環(huán)調(diào)用 MAX-HEAPIPY過程來(lái)完成的 因此我們先介紹MAX-HEAPIPY:

MAX-HEAPIPY是用于維護(hù)最大堆性質(zhì)的重要過程拍顷。它的輸入為一個(gè)數(shù)組A和一個(gè)下標(biāo)i抚太,在調(diào)用MAX-HEAPIPY的時(shí)候,我們假定根節(jié)點(diǎn)為L(zhǎng)eft[i]和Right[i]的子樹都是最大堆昔案,但這時(shí)A[i]可能小于其孩子節(jié)點(diǎn)尿贫,這樣就違背了最大堆的性質(zhì)。MAX-HEAPIPY通過讓A[i]的值在堆中“逐級(jí)下降”從而使得以下標(biāo)i為根節(jié)點(diǎn)的子樹重新遵循最大堆的性質(zhì)踏揣。

MAX-HEAPIPY偽代碼如下:

  1. l = LEFT(i)
  2. r = RIGHT(i)
  3. if l <= A.heap-size && A[l] > A [i]
  4. largest = l;
  5. else largest = i
  6. if(r<= A.heap-size &&  A[r] > A [i]
  7. largest = r
  8. if largest != i
  9. exchange A[i] with A[largest]
  10. MAX-HEAP(A,largest)

由以上偽代碼可知維護(hù)最大堆性質(zhì)就是將i節(jié)點(diǎn)開始遍歷它的左右子樹庆亡,從未保證i節(jié)點(diǎn)是這棵子樹的最大子節(jié)點(diǎn),由于在前面的假定中i的子樹已經(jīng)是一棵滿足最大堆的二叉樹因此經(jīng)過MAX-HEAP過程加上i這一層后繼續(xù)滿足最大堆的特性

BUILD-MAX-HEAP 創(chuàng)建最大堆就是將一個(gè)大小n=Array.length的數(shù)組A[0,1...n-1]轉(zhuǎn)換為最大堆的過程捞稿。
用偽代碼表示創(chuàng)建最大堆如下
BUILD-MAX—HEAP(A)

  1. A.heap-size = A.lenth
  2. for i = A.length/2 down to 0
  3. MAX-HEAPRIFY(A,i)

由以上偽代碼可知?jiǎng)?chuàng)建最大堆過程就是從樹的底部向樹的根部遍歷調(diào)用MAX-HEAPRIFY方法來(lái)完成的A.length/2 表示從樹的倒數(shù)第二層開始調(diào)用MAX-HEAP 從底部往上通過循環(huán)逐漸將一棵二叉樹變?yōu)樽畲蠖延帜薄T谶@個(gè)過程中先是把倒數(shù)第二層的子樹變換為最大堆,然后根據(jù)MAX-HEAP的假定在最底層滿足最大堆后遍歷倒數(shù)第二層時(shí) 這樣遍歷倒數(shù)第三層進(jìn)行MAX-HEAP時(shí)倒數(shù)第三層也滿足了最大堆的特性括享,因此建立最大堆是一個(gè)從底部網(wǎng)上逐級(jí)滿足最大堆的特性搂根,遍歷完根節(jié)點(diǎn)后整棵二叉樹就成為了一棵最大堆。

最后我們來(lái)看HEAP-SORT即堆排序就非常簡(jiǎn)單了
先給出偽代碼
HEAP-SORT(A)

  1. BUILD-MAX-HEAP(A)
  2. for(A.length dowm to 1
  3. exchange A[i] whih A[0]
  4. MAX-HEAPIFY(A,0)
    從以上偽代碼可以看出堆排序是怎么利用堆這種數(shù)據(jù)結(jié)構(gòu)進(jìn)行排序以及非常巧妙的利用了最大堆的特性非常高效的就將一個(gè)序列變?yōu)榱艘粋€(gè)有序的序列铃辖。
    首先是根據(jù)輸入數(shù)組建立一個(gè)最大堆剩愧,根據(jù)最大堆的性質(zhì)此時(shí)序列最大元素就是根節(jié)點(diǎn)的元素,這時(shí)把根節(jié)點(diǎn)移到最后一個(gè)節(jié)點(diǎn)以后娇斩,根節(jié)點(diǎn)的左右子樹仍然滿足最大堆的條件仁卷,這時(shí)在調(diào)用MAX-HEAPIFY就可以很快的讓整棵樹重新成為一棵最大堆。經(jīng)過遍歷和交換過程中A[0]到A[i-1]最大堆 而A[i] 到A[A.length-1]為從小到大排列的數(shù)組,遍歷過程就是不斷的取出處于根節(jié)點(diǎn)的最大元素犬第,然后將剩余元素從未維護(hù)為最大堆的過程锦积。

樣整個(gè)堆排序的過程就介紹完了,了解了堆排序后是不是得感嘆發(fā)明此算法的人是有多聰明呀,想到這么巧妙數(shù)據(jù)構(gòu)歉嗓,和利用該數(shù)據(jù)結(jié)構(gòu)巧妙高效的完成了排序丰介,而我等普通人不是不奢望能發(fā)明算法,但能夠把一種算法理解透并能夠靈活運(yùn)用到實(shí)際的項(xiàng)目中也是不錯(cuò)的了鉴分。

算法復(fù)時(shí)間空間復(fù)雜度分析

  1. 空間復(fù)雜度

于排序過程是在原數(shù)組上對(duì)元素進(jìn)行處理哮幢,僅僅只是在元素交換時(shí)開辟了常數(shù)個(gè)元素空間,因此堆排序空間復(fù)雜度很簡(jiǎn)單就是O(1)

  1. 時(shí)間復(fù)雜度
    由上面的堆排序的偽代碼可知首先建立最大堆是逐層建立根據(jù)完全二叉樹的性質(zhì)我們很容易得到完全二叉樹的深度為lg(n) 而遍歷一趟的時(shí)間復(fù)雜度為O(n),遍歷趟數(shù)為lg(n)因此堆排序的時(shí)間復(fù)雜度為O(nlgn)

END Talk is cheap show me your code

void maxHeapify(int *unSortArray, int root, int bottom) {
int rootValue = unSortArray[root];
int left = root * 2 + 1;
while (left <= bottom) {
    if (left < bottom) {
        if (unSortArray[left] < unSortArray[left + 1]) {
            left = left + 1;
        }
    }

    if (rootValue < unSortArray[left]) {
        unSortArray[root] = unSortArray[left];
        root = left;
        left = root * 2 + 1;
    } else {
        left = bottom + 1;
    }
}

unSortArray[root] = rootValue;
}

void buildMaxHeap(int *unSortArray, int arraySize) {
for (int i = arraySize / 2 - 1; i >= 0; i--) {
    maxHeapify(unSortArray, i, arraySize - 1);
    }
}

void heapSortByMaxHeap(int *unSortArray, int arraySize) {
buildMaxHeap(unSortArray, arraySize);
for (int i = arraySize - 1; i >= 0; i--) {
    int max = unSortArray[0];
    unSortArray[0] = unSortArray[i];
    unSortArray[i] = max;
    maxHeapify(unSortArray, 0, i - 1);
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末志珍,一起剝皮案震驚了整個(gè)濱河市橙垢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌伦糯,老刑警劉巖柜某,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嗽元,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡喂击,警方通過查閱死者的電腦和手機(jī)剂癌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)翰绊,“玉大人珍手,你說(shuō)我怎么就攤上這事〈亲觯” “怎么了琳要?”我有些...
    開封第一講書人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)秤茅。 經(jīng)常有香客問我稚补,道長(zhǎng),這世上最難降的妖魔是什么框喳? 我笑而不...
    開封第一講書人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任课幕,我火速辦了婚禮,結(jié)果婚禮上五垮,老公的妹妹穿的比我還像新娘乍惊。我一直安慰自己,他們只是感情好放仗,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開白布润绎。 她就那樣靜靜地躺著,像睡著了一般诞挨。 火紅的嫁衣襯著肌膚如雪莉撇。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評(píng)論 1 290
  • 那天惶傻,我揣著相機(jī)與錄音棍郎,去河邊找鬼。 笑死银室,一個(gè)胖子當(dāng)著我的面吹牛涂佃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蜈敢,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼辜荠,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了扶认?” 一聲冷哼從身側(cè)響起侨拦,我...
    開封第一講書人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤殊橙,失蹤者是張志新(化名)和其女友劉穎辐宾,沒想到半個(gè)月后狱从,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡叠纹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年季研,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片誉察。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡与涡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出持偏,到底是詐尸還是另有隱情驼卖,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布鸿秆,位于F島的核電站酌畜,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏卿叽。R本人自食惡果不足惜桥胞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望考婴。 院中可真熱鬧贩虾,春花似錦、人聲如沸沥阱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)考杉。三九已至屁使,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間奔则,已是汗流浹背蛮寂。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留易茬,地道東北人酬蹋。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像抽莱,于是被迫代替她去往敵國(guó)和親范抓。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350

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

  • 概述 排序有內(nèi)部排序和外部排序食铐,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序匕垫,而外部排序是因排序的數(shù)據(jù)很大,一次不能容納全部...
    蟻前閱讀 5,170評(píng)論 0 52
  • 概述:排序有內(nèi)部排序和外部排序虐呻,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序象泵,而外部排序是因排序的數(shù)據(jù)很大寞秃,一次不能容納全部...
    每天刷兩次牙閱讀 3,729評(píng)論 0 15
  • 1 序 2016年6月25日夜,帝都偶惠,天下著大雨春寿,拖著行李箱和同學(xué)在校門口照了最后一張合照,搬離寢室打車去了提前租...
    RichardJieChen閱讀 5,083評(píng)論 0 12
  • retain cycle 會(huì)造成內(nèi)存溢出忽孽,嚴(yán)重情況會(huì)引起崩潰绑改。一般注意點(diǎn)也不會(huì)發(fā)生,但在網(wǎng)絡(luò)連接比較多的地方就會(huì)不...
    natewang閱讀 3,432評(píng)論 0 3
  • 昨天28號(hào)是七夕情人節(jié)兄一,你懂的厘线,該干啥干啥。 秦觀的那首詞出革,金風(fēng)玉露一相逢便勝卻世間無(wú)數(shù)皆的,聽了讓人不禁遐想萬(wàn)端,風(fēng)...
    老趙愛生活閱讀 274評(píng)論 0 0