3. 歸并排序

歸并排序以?(N logN)最壞情形運(yùn)行時(shí)間運(yùn)行,而所使用的比較次數(shù)幾乎是最優(yōu)的鄙漏。

這個(gè)算法的基本操作是合并兩個(gè)已排序的表恃轩。

歸并排序大致分為兩種

  1. 自頂向下(遞歸)
  2. 自底向上(迭代)

1. 實(shí)現(xiàn)

1.1 自頂向下遞歸排序

自頂向下的遞歸排序主要使用的是分治思想,代碼實(shí)現(xiàn)較為復(fù)雜脆侮。

1.1.1 實(shí)現(xiàn)流程

  1. 分配等同于待排序大小的內(nèi)存空間瞎领。(必須且不會(huì)更少)
  2. 對(duì)半分割泌辫,成兩個(gè)不同的部分。
  3. 重復(fù)2步驟直至不能再分割九默。
  4. 對(duì)兩部分分別排序震放。
  5. 合并排序兩部分。
  6. 返回上一級(jí)遞歸驼修。

1.1.2 代碼實(shí)現(xiàn)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef int ElementType;

/* 歸并排序入口程序 */
void MergeSort(ElementType source[], int n);

/* 二分程序 */
static void MSort(ElementType source[], ElementType tmpArr[], int left, int right);

/* 排序合并程序 */
static void Merge(ElementType source[], ElementType tmpArr[], int left, int rightPos, int right);

void MergeSort(ElementType source[], int n) {
    ElementType *tmpArr;

    tmpArr = (ElementType *) malloc(n * sizeof(ElementType));
    if (tmpArr != NULL) {
        MSort(source, tmpArr, 0, n - 1);
        free(tmpArr);
    } else {
        printf("No Space for tmp array!!!");
        exit(EXIT_FAILURE);
    }
}


static void MSort(ElementType source[], ElementType tmpArr[], int left, int right) {
    int center;

    if (left < right) {
        center = (left + right) / 2;
        MSort(source, tmpArr, left, center);
        MSort(source, tmpArr, center + 1, right);
        Merge(source, tmpArr, left, center + 1, right);
    }
}

static void Merge(ElementType source[], ElementType tmpArr[], int left, int rightPos, int right) {

    int tmpLeft = left;
    int leftEnd = rightPos - 1;
    int tmpRight = rightPos;
    int Num = right - left + 1;

    while (tmpLeft <= leftEnd && tmpRight <= right) {
        if (source[tmpLeft] < source[tmpRight]) {
            tmpArr[left++] = source[tmpLeft++];
        } else {
            tmpArr[left++] = source[tmpRight++];
        }
    }

    while (tmpLeft <= leftEnd) {
        tmpArr[left++] = source[tmpLeft++];
    }

    while (tmpRight <= right) {
        tmpArr[left++] = source[tmpRight++];
    }

    /* 把排好的tmp復(fù)制回原數(shù)組,由于左標(biāo)志已經(jīng)被移動(dòng)因此用右標(biāo)志向左移動(dòng)倒敘放 */
    for (int i = 0; i < Num; ++i, right--) {
        source[right] = tmpArr[right];
    }

}

1.1.3 自頂向下縮短運(yùn)行時(shí)間的幾個(gè)Tips

1.1.3.1 對(duì)小規(guī)模數(shù)組使用插入排序

長(zhǎng)度小于15殿遂,一般可將時(shí)間縮短10%~15%。

1.1.3.2 測(cè)試數(shù)組是否已經(jīng)有序

如果a[mid]小于等于a[mid+1]乙各,我們就認(rèn)為數(shù)組已經(jīng)是有序的并跳過(guò)merge()方法墨礁。

1.1.3.3 不將元素賦值到輔助數(shù)組

部分歸并排序?qū)崿F(xiàn)中會(huì)現(xiàn)將數(shù)組復(fù)制到輔助數(shù)組排序后再?gòu)?fù)制回去(本例中沒(méi)有這么做)。這種操作是可以避免的耳峦。

1.2 自低向上歸并排序

自底向上的思想是恩静,先兩兩合并最小的,再四四合并相對(duì)小的妇萄,如此這般蜕企,直到我們將整個(gè)數(shù)組歸并到一起。

1.2.1 實(shí)現(xiàn)流程

  1. 將序列每相鄰兩個(gè)數(shù)字進(jìn)行歸并操作冠句,形成 floor(n/2)個(gè)序列,排序后每個(gè)序列包含兩個(gè)元素
  2. 將上述序列再次歸并懦底,形成 floor(n/4)個(gè)序列唇牧,每個(gè)序列包含四個(gè)元素
  3. 重復(fù)步驟2,直到所有元素排序完畢

1.2.2 算法圖解

插入排序
插入排序

1.2.3 代碼實(shí)現(xiàn)

int min(int x, int y) {
    return x < y ? x : y;
}
void merge_sort(int arr[], int len) {
    int* a = arr;
    int* b = (int*) malloc(len * sizeof(int*));
    int seg, start;
    for (seg = 1; seg < len; seg += seg) {
        for (start = 0; start < len; start += seg + seg) {
            int low = start, mid = min(start + seg, len), high = min(start + seg + seg, len);
            int k = low;
            int start1 = low, end1 = mid;
            int start2 = mid, end2 = high;
            while (start1 < end1 && start2 < end2)
                b[k++] = a[start1] < a[start2] ? a[start1++] : a[start2++];
            while (start1 < end1)
                b[k++] = a[start1++];
            while (start2 < end2)
                b[k++] = a[start2++];
        }
        int* temp = a;
        a = b;
        b = temp;
    }
    if (a != arr) {
        int i;
        for (i = 0; i < len; i++)
            b[i] = a[i];
        b = a;
    }
    free(b);
}

2. 時(shí)間復(fù)雜度

最差時(shí)間復(fù)雜度 ?( nlog n )
最優(yōu)時(shí)間復(fù)雜度 ?( n )
平均時(shí)間復(fù)雜度 ?( nlog n )

最差空間復(fù)雜度 ?( n )

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末聚唐,一起剝皮案震驚了整個(gè)濱河市丐重,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌杆查,老刑警劉巖扮惦,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異亲桦,居然都是意外死亡崖蜜,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén)客峭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)豫领,“玉大人,你說(shuō)我怎么就攤上這事舔琅〉瓤郑” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵备蚓,是天一觀的道長(zhǎng)课蔬。 經(jīng)常有香客問(wèn)我,道長(zhǎng)郊尝,這世上最難降的妖魔是什么购笆? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮虚循,結(jié)果婚禮上同欠,老公的妹妹穿的比我還像新娘。我一直安慰自己横缔,他們只是感情好铺遂,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著茎刚,像睡著了一般襟锐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上膛锭,一...
    開(kāi)封第一講書(shū)人閱讀 49,166評(píng)論 1 284
  • 那天粮坞,我揣著相機(jī)與錄音蚊荣,去河邊找鬼。 笑死莫杈,一個(gè)胖子當(dāng)著我的面吹牛互例,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播筝闹,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼媳叨,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了关顷?” 一聲冷哼從身側(cè)響起糊秆,我...
    開(kāi)封第一講書(shū)人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎议双,沒(méi)想到半個(gè)月后痘番,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡平痰,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年夫偶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片觉增。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡兵拢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出逾礁,到底是詐尸還是另有隱情说铃,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布嘹履,位于F島的核電站腻扇,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏砾嫉。R本人自食惡果不足惜幼苛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望焕刮。 院中可真熱鬧舶沿,春花似錦、人聲如沸配并。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)溉旋。三九已至畸冲,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背邑闲。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工算行, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人苫耸。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓州邢,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親鲸阔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子偷霉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

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

  • 1.插入排序—直接插入排序(Straight Insertion Sort) 基本思想: 將一個(gè)記錄插入到已排序好...
    依依玖玥閱讀 1,239評(píng)論 0 2
  • 概述:排序有內(nèi)部排序和外部排序迄委,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序褐筛,而外部排序是因排序的數(shù)據(jù)很大,一次不能容納全部...
    每天刷兩次牙閱讀 3,727評(píng)論 0 15
  • 接下來(lái)準(zhǔn)備學(xué)習(xí)一下歸并排序去別的blog看了一段叙身,很多博客概括介紹歸并的時(shí)候是這樣子的: 基本理念:分治思想(di...
    阿飛不理飛閱讀 292評(píng)論 0 0
  • Ba la la la ~ 讀者朋友們渔扎,你們好啊,又到了冷鋒時(shí)間信轿,話不多說(shuō)晃痴,發(fā)車! 1.冒泡排序(Bub...
    王飽飽閱讀 1,788評(píng)論 0 7
  • 仲夏終于耐受不住炎熱的炙烤迎來(lái)了一場(chǎng)傾盆大雨财忽,偌大的京城在呼嘯的狂風(fēng)中顫抖飄搖倘核,像是揭開(kāi)了天穹的蓋子一樣灌入人間,...
    北城琴聲閱讀 379評(píng)論 1 6