3.歸并排序(Merge sort)

題目

設(shè)計(jì)一個(gè)算法可將{4, 2, -3, 6, 1} (或其他亂序的數(shù)組)按升序排序得到 {-3, 1, 2, 4, 6}搪泳。

解題思路

1.將數(shù)組分成兩組
2.每一組各自排序吨掌,怎么排?用同樣的方法排丐枉,重復(fù)動(dòng)作(1)分成兩組...(遞歸)
3.合并:經(jīng)過(guò)1盟萨,2動(dòng)作的遞歸后岔绸,最后會(huì)變成一顆樹(shù)蔽莱,再?gòu)臉?shù)的最底層開(kāi)始每?jī)蓚€(gè)節(jié)點(diǎn)開(kāi)始合并, 合并的同時(shí)做好排序逛万,當(dāng)合并到最頂層時(shí)整個(gè)數(shù)組就排序好了泳猬。
如何排序:每個(gè)節(jié)點(diǎn)的數(shù)據(jù)都是由上一次合并后得到的是排序好的!我們可以把兩個(gè)節(jié)點(diǎn)想象為有兩個(gè)數(shù)組宇植,每次對(duì)比兩個(gè)數(shù)組的第一個(gè)元素取出較小的元素放到另一個(gè)數(shù)組里得封,當(dāng)兩個(gè)數(shù)組的元素都被取完了就完成排序和合并了。

(1),(2)


1.png

(3)


2.png

(排序合并)
排序.png

Code


    public void mergeSort(int[] arr) {
        if (arr == null || arr.length <= 1) return;

        int[] helper = new int[arr.length];
        mergeSort(arr, 0, arr.length - 1, helper);
    }


    //    1.將數(shù)組分成兩組
//    2.每一組各自排序指郁,怎么排?用同樣的方法排忙上,重復(fù)動(dòng)作(1)分成兩組...(遞歸)
    private void mergeSort(int[] arr, int left, int right, int[] helper) {
        //base case:如果節(jié)點(diǎn)只剩下一個(gè)元素了則停止分裂
        if (left >= right) {
            return;
        }

        //防止大數(shù)溢出,如果left和right都等于Integer.MAX_VALUE那么它們相加就會(huì)超出int的取值范圍導(dǎo)致溢出
        int mid = left + (right - left) / 2;
        //分組
        mergeSort(arr, left, mid, helper);
        mergeSort(arr, mid + 1, right, helper);

        //合并
        megre(arr, left, mid, right, helper);
    }

    //3.合并:經(jīng)過(guò)1,2動(dòng)作的遞歸后闲坎,最后會(huì)變成一顆樹(shù)晨横,再?gòu)臉?shù)的最底層開(kāi)始每?jī)蓚€(gè)節(jié)點(diǎn)開(kāi)始合并,
// 合并的同時(shí)做好排序洋腮,當(dāng)合并到最頂層時(shí)整個(gè)數(shù)組就排序好了。
// 如何排序:每個(gè)節(jié)點(diǎn)的數(shù)據(jù)都是由上一次合并后得到的是排序好的手形!
// 我們可以把兩個(gè)節(jié)點(diǎn)想象為有兩個(gè)數(shù)組,每次對(duì)比兩個(gè)數(shù)組的第一個(gè)元素取出較小的元素放到另一個(gè)數(shù)組里悯恍,
// 當(dāng)兩個(gè)數(shù)組的元素都被取完了就完成和排序和合并了库糠。
    private void megre(int[] arr, int left, int mid, int right, int[] helper) {
        for (int i = 0; i < arr.length; i++) {
            helper[i] = arr[i];
        }
        int l = left;//表示左邊數(shù)組的指針
        int r = mid + 1;//表示右邊數(shù)組的指針
        int k = left;//存放排好序的元素的數(shù)組的指針
        while (l <= mid && r <= right) {//當(dāng)有其中一個(gè)指針先走完則停止while循環(huán)
            if (helper[l] < helper[r]) {
                arr[k] = helper[l];//取出較小的元素放到另一個(gè)數(shù)組里
                k++;//指針右移
                l++;//指針右移
            } else {
                arr[k] = helper[r];//取出較小的元素放到另一個(gè)數(shù)組里
                k++;//指針右移
                r++;//指針右移
            }
        }

        //如果r指針先走完l指針還未走完則直接將元素放到另一個(gè)數(shù)組的尾部
        while (l <= mid) {
            arr[k++] = helper[l++];
        }

    }

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

時(shí)間復(fù)雜度:

Merge sort的時(shí)空復(fù)雜度分析比較復(fù)雜,我們可以把這個(gè)算法的執(zhí)行過(guò)程分為兩個(gè)階段來(lái)看:
第一個(gè)階段:分組


1.png

從這張圖中我們可以看出分組時(shí)的每一層的節(jié)點(diǎn)數(shù)都是上一層的double,所以總共的節(jié)點(diǎn)數(shù)是:1+2+4+8+...+n/2 = 1+1+2+4+8+...+n/2-1 = n/2 + n/2 -1 = n-1,忽略對(duì)復(fù)雜度影響較小的系數(shù)所以總節(jié)點(diǎn)是n涮毫,而且每次分組只執(zhí)行了一行求mid的代碼:
int mid = left + (right - left) / 2;也就是O(1), 所以第一階段的時(shí)間復(fù)雜度是O(n*1) = O(n);

第二階段:合并
我們來(lái)看看合并的核心代碼

        while (l <= mid && r <= right) {
            if (helper[l] < helper[r]) {
                arr[k] = helper[l];
                k++;
                l++;
            } else {
                arr[k] = helper[r];
                k++;
                r++;
            }
        }

是一個(gè)while循環(huán)瞬欧,隨著arr數(shù)組的長(zhǎng)度的增加while循環(huán)的次數(shù)是線性增長(zhǎng)的所以我們得出這段代碼的復(fù)雜度是O(n), 其實(shí)只要是while循環(huán)或者單層for循環(huán)我們都可以認(rèn)為復(fù)雜度就是O(n),既然每一層的復(fù)雜度是O(n)那么我們只要算出總共有多少層就可以算出第二階段的時(shí)間復(fù)雜度罢防,如上圖我們假設(shè)這是一棵滿的二叉樹(shù)那么就總共有l(wèi)og2n層艘虎,或者假設(shè)數(shù)組的長(zhǎng)度n=8每次二分總共可以分裂log2n次,所以第二階段的時(shí)間復(fù)雜度是O(nlgn). (lgn = log2n)

結(jié)論:所以merge sort的時(shí)間復(fù)雜度是O(n)+O(nlgn),因?yàn)槲覀冴P(guān)心的是漸進(jìn)性復(fù)雜度有高次項(xiàng)在的時(shí)候可以忽略低次項(xiàng)咒吐,所以O(shè)(n)<O(nlgn)取O(nlgn)野建。

空間復(fù)雜度:

因?yàn)槭莔egre sort是遞歸實(shí)現(xiàn)的,所以空間復(fù)雜度與其遞歸的層數(shù)相關(guān)恬叹,先普及一個(gè)概念: 在java中每一個(gè)函數(shù)的開(kāi)始和結(jié)束都代表著在JVM Stack中一個(gè)棧幀(stack frame)的入棧和出棧候生,遞歸是函數(shù)自己調(diào)用自己,每次調(diào)用自己都會(huì)往JVM Stack中壓入一個(gè)stack frame


stack_frame.png

因?yàn)閙egre sort的遞歸樹(shù)總共有l(wèi)gn層绽昼,所以我們最多時(shí)使用了lgn個(gè)stack frame唯鸭,so空間復(fù)雜度是O(lgn)。
但是我們這段merge sort代碼的空間復(fù)雜度并不是O(lgn)而是O(n),
為什么呢硅确?因?yàn)槲覀兂吮仨氁褂玫降木植孔兞客膺€創(chuàng)建了一個(gè)輔助我們計(jì)算的數(shù)組int[] helper = new int[arr.length]; 目溉,所以空間復(fù)雜度應(yīng)該是:O(lgn)+O(n)而O(lgn)<O(n), 所以我們megre sort的空間復(fù)雜度是O(n)。(我們關(guān)心的是漸進(jìn)性復(fù)雜度有高次項(xiàng)在的時(shí)候可以忽略低次項(xiàng))

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末菱农,一起剝皮案震驚了整個(gè)濱河市缭付,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌大莫,老刑警劉巖蛉腌,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異只厘,居然都是意外死亡烙丛,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén)羔味,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)河咽,“玉大人,你說(shuō)我怎么就攤上這事赋元⊥罚” “怎么了飒房?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)媚值。 經(jīng)常有香客問(wèn)我狠毯,道長(zhǎng),這世上最難降的妖魔是什么褥芒? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任嚼松,我火速辦了婚禮,結(jié)果婚禮上锰扶,老公的妹妹穿的比我還像新娘献酗。我一直安慰自己,他們只是感情好坷牛,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布罕偎。 她就那樣靜靜地躺著,像睡著了一般京闰。 火紅的嫁衣襯著肌膚如雪颜及。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,156評(píng)論 1 308
  • 那天忙干,我揣著相機(jī)與錄音器予,去河邊找鬼。 笑死捐迫,一個(gè)胖子當(dāng)著我的面吹牛乾翔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播施戴,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼反浓,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了赞哗?” 一聲冷哼從身側(cè)響起雷则,我...
    開(kāi)封第一講書(shū)人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎肪笋,沒(méi)想到半個(gè)月后月劈,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡藤乙,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年猜揪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片坛梁。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡而姐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出划咐,到底是詐尸還是另有隱情拴念,我是刑警寧澤钧萍,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布,位于F島的核電站政鼠,受9級(jí)特大地震影響风瘦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜公般,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一弛秋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧俐载,春花似錦、人聲如沸登失。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)揽浙。三九已至状婶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間馅巷,已是汗流浹背膛虫。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留钓猬,地道東北人稍刀。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像敞曹,于是被迫代替她去往敵國(guó)和親账月。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359

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

  • 排序問(wèn)題:### 輸入:n個(gè)數(shù)的一個(gè)序列 輸出:輸入序列的一個(gè)排列 澳迫,滿足a1'<=a2'<=,...<=an'下...
    陳繼科閱讀 1,155評(píng)論 0 0
  • 總結(jié)一下常見(jiàn)的排序算法局齿。 排序分內(nèi)排序和外排序。內(nèi)排序:指在排序期間數(shù)據(jù)對(duì)象全部存放在內(nèi)存的排序橄登。外排序:指在排序...
    jiangliang閱讀 1,350評(píng)論 0 1
  • 1 初級(jí)排序算法 排序算法關(guān)注的主要是重新排列數(shù)組元素抓歼,其中每個(gè)元素都有一個(gè)主鍵。排序算法是將所有元素主鍵按某種方...
    深度沉迷學(xué)習(xí)閱讀 1,413評(píng)論 0 1
  • Chapter 2 插入排序 線性查找 選擇算法 歸并排序算法 二分查找算法 冒泡排序 插入排序 循環(huán)不...
    只是無(wú)情緒閱讀 1,457評(píng)論 0 1
  • 我焦慮的是什么拢锹?我的焦慮有沒(méi)有改變什么谣妻?我現(xiàn)在在做什么?對(duì)事情有什么實(shí)質(zhì)性的變化嗎面褐?如果沒(méi)有什么實(shí)質(zhì)性的改變拌禾,我的...
    以愛(ài)之名2017閱讀 817評(píng)論 0 0