C語言:十種排序(五) - 歸并排序

前言

一種將無序數(shù)組進(jìn)行排序的方法。

歸并排序,相關(guān)定義可以參考wiki:
https://zh.wikipedia.org/wiki/%E5%BD%92%E5%B9%B6%E6%8E%92%E5%BA%8F

主要思想有2:

  1. 有序數(shù)組派哲。在插入排序中也有此思想
  2. 合并兩兩有序數(shù)組蹭睡,通過引入額外的臨時數(shù)組實現(xiàn)状您。

本文代碼基本未優(yōu)化,是一種原始邏輯的體現(xiàn)捐韩。

環(huán)境

編輯器:vs2019
文件:.c類型

正文

代碼參考:

#include <stdio.h>


// 歸并排序,主要思想:合并兩個有序數(shù)組鹃锈,通過引入額外的臨時數(shù)組實現(xiàn)荤胁。
// 遞歸歸并排序,每一次遞歸屎债,改變一次有序數(shù)組長度仅政。


// 普通歸并排序垢油,從小到大
void merge_sort_normal(int source_array[], int source_array_length)
{
    int start; // 兩兩分組的總起點(diǎn)索引
    int* b = (int*)malloc(source_array_length * sizeof(int)); // 引入臨時數(shù)組, 臨時數(shù)組存放每次排序后的結(jié)果已旧。

    // 分組, 每組元素數(shù)量:1, 2, 4, 8 ...
    for (int gap = 1; gap < source_array_length; gap += gap)
    {
        // 合并兩兩分組
        for (start = 0; start < source_array_length; start += gap * 2)
        {
            // 臨時數(shù)組的索引
            int b_index = start;

            // 左邊數(shù)組的起點(diǎn)索引
            int start_left = start;
            // 左邊數(shù)組的結(jié)束索引
            int end_left = start_left + gap - 1;

            // 右邊數(shù)組的起點(diǎn)索引
            int start_right = start + gap;
            // 右邊數(shù)組的結(jié)束索引
            int end_right = start_right + gap - 1;

            // 1. 當(dāng)左邊數(shù)組不滿時,或沒有右邊數(shù)組時
            if (end_left >= source_array_length - 1)
            {
                for (; b_index < source_array_length; b_index++)
                {
                    b[b_index] = source_array[b_index];
                }
                break;
            }

            // 2. 當(dāng)右邊數(shù)組不滿時
            if (end_right > source_array_length - 1)
            {
                end_right = source_array_length - 1;
            }

            // 3. 開始合并兩數(shù)組
            while (start_left <= end_left && start_right <= end_right)
            {
                if (source_array[start_right] > source_array[start_left])
                {
                    b[b_index] = source_array[start_left];
                    b_index++;
                    start_left++;
                }
                else
                {
                    b[b_index] = source_array[start_right];
                    b_index++;
                    start_right++;
                }
            }

            // 4. 經(jīng)過【3】步驟的合并授霸,存在某個數(shù)組沒有完全插入臨時數(shù)組的情況
            // 當(dāng)左數(shù)組未插完
            while (start_left <= end_left)
            {
                b[b_index] = source_array[start_left];
                b_index++;
                start_left++;
            }
            // 當(dāng)右數(shù)組未插完
            while (start_right <= end_right)
            {
                b[b_index] = source_array[start_right];
                b_index++;
                start_right++;
            }       
        }

        // 每次兩兩分組合并后, 都需要將臨時數(shù)組的值賦值回原數(shù)組蒸走。
        if (source_array != b)
        {
            for (int i = 0; i < source_array_length; i++)
            {
                source_array[i] = b[i];
            }
        }
    }
}


// 遞歸歸并排序狰右,從小到大
// 其中額外引入gap,初始值設(shè)為1
void merge_sort_recursive(int source_array[], int source_array_length, int gap)
{
    int start;
    int* b = (int*)malloc(source_array_length * sizeof(int));

    for (start = 0; start < source_array_length; start += gap * 2)
    {
        int b_index = start;

        int start_left = start;
        int end_left = start_left + gap - 1;

        int start_right = start + gap;
        int end_right = start_right + gap - 1;

        if (end_left >= source_array_length - 1)
        {
            for (; b_index < source_array_length; b_index++)
            {
                b[b_index] = source_array[b_index];
            }
            break;
        }

        if (end_right > source_array_length - 1)
        {
            end_right = source_array_length - 1;
        }

        while (start_left <= end_left && start_right <= end_right)
        {
            if (source_array[start_right] > source_array[start_left])
            {
                b[b_index] = source_array[start_left];
                b_index++;
                start_left++;
            }
            else
            {
                b[b_index] = source_array[start_right];
                b_index++;
                start_right++;
            }
        }

        while (start_left <= end_left)
        {
            b[b_index] = source_array[start_left];
            b_index++;
            start_left++;
        }
        while (start_right <= end_right)
        {
            b[b_index] = source_array[start_right];
            b_index++;
            start_right++;
        }
    }

    if (source_array != b)
    {
        for (int i = 0; i < source_array_length; i++)
        {
            source_array[i] = b[i];
        }
    }

    gap += gap;
    if (gap >= source_array_length)
    {
        return 0;
    }
    merge_sort_recursive(source_array, source_array_length, gap);

}


int* upset_array(int source_list[], int source_list_length)
{
    for (int i = 0; i < source_list_length; i++)
    {
        int rand_index = rand() % source_list_length;
        int tmp_value = source_list[i];
        source_list[i] = source_list[rand_index];
        source_list[rand_index] = tmp_value;
    }
    return source_list;
}


int main()
{
    // 生成隨機(jī)測試列表
    int test_list[20];
    int test_list_length = sizeof(test_list) / sizeof(int);
    printf("測試列表: \n");
    for (int i = 0; i < test_list_length; i++)
    {
        test_list[i] = rand() % 100;
        printf("%d ", test_list[i]);
    }
    printf("\n");


    // 普通歸并排序
    merge_sort_normal(test_list, test_list_length);
    printf("普通歸并排序結(jié)果: \n");
    for (int i = 0; i < test_list_length; i++)
    {
        printf("%d ", test_list[i]);
    }
    printf("\n");


    // 打亂數(shù)組
    upset_array(test_list, test_list_length);
    printf("打亂測試列表: \n");
    for (int i = 0; i < test_list_length; i++)
    {
        printf("%d ", test_list[i]);
    }
    printf("\n");

    // 遞歸歸并排序
    merge_sort_recursive(test_list, test_list_length, 1);
    printf("遞歸歸并排序結(jié)果: \n");
    for (int i = 0; i < test_list_length; i++)
    {
        printf("%d ", test_list[i]);
    }
    printf("\n");


    return 0;
}


執(zhí)行結(jié)果參考:


image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末秸讹,一起剝皮案震驚了整個濱河市檀咙,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌璃诀,老刑警劉巖弧可,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異劣欢,居然都是意外死亡棕诵,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進(jìn)店門凿将,熙熙樓的掌柜王于貴愁眉苦臉地迎上來校套,“玉大人,你說我怎么就攤上這事牧抵〉殉祝” “怎么了?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵犀变,是天一觀的道長妹孙。 經(jīng)常有香客問我,道長获枝,這世上最難降的妖魔是什么蠢正? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮省店,結(jié)果婚禮上机隙,老公的妹妹穿的比我還像新娘。我一直安慰自己萨西,他們只是感情好有鹿,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著谎脯,像睡著了一般葱跋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天娱俺,我揣著相機(jī)與錄音稍味,去河邊找鬼。 笑死荠卷,一個胖子當(dāng)著我的面吹牛模庐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播油宜,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼掂碱,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了慎冤?” 一聲冷哼從身側(cè)響起疼燥,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蚁堤,沒想到半個月后醉者,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡披诗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年撬即,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片呈队。...
    茶點(diǎn)故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡剥槐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出掂咒,到底是詐尸還是另有隱情,我是刑警寧澤迈喉,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布绍刮,位于F島的核電站,受9級特大地震影響挨摸,放射性物質(zhì)發(fā)生泄漏孩革。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一得运、第九天 我趴在偏房一處隱蔽的房頂上張望膝蜈。 院中可真熱鬧,春花似錦熔掺、人聲如沸饱搏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽推沸。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鬓催,已是汗流浹背肺素。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留宇驾,地道東北人倍靡。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像课舍,于是被迫代替她去往敵國和親塌西。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評論 2 355

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