排序算法3|歸并排序(C#)

今天我們的目標(biāo)是:歸并排序。要理解這種排序,首先我們先了解一下歸并:

歸并:

現(xiàn)在我們要求將兩個(gè)從小到大排列的有序數(shù)組歸并為一個(gè)從小到大排序的有序數(shù)組。想想怎么辦呕屎?常規(guī)做法就是:
1、 創(chuàng)建一個(gè)新數(shù)組敬察,長(zhǎng)度是兩個(gè)數(shù)組的長(zhǎng)度之和秀睛。
2、 運(yùn)用三個(gè)指針莲祸,分別指向三個(gè)數(shù)組的頭部蹂安,然后比較需要?dú)w并的數(shù)組兩個(gè)指針指向的數(shù)字,得到較小者锐帜,將較小者放在新數(shù)組指針指向的位置田盈,然后向后移動(dòng)較小者數(shù)組指針,和新數(shù)組指針缴阎。
3允瞧、 重復(fù)步驟2,直到一個(gè)數(shù)組比較完畢。將未排完數(shù)組述暂,后續(xù)的數(shù)字排到新數(shù)組的尾部痹升。歸并結(jié)束。

代碼:

       public static int[] Merge(int[] arr1, int[] arr2)
        {
            int length1 = arr1.Length;
            int length2 = arr2.Length;
            
            int[] arr = new int[length1 + length2];
            int index = 0;
            int i = 0;
            int j = 0;

            //從前往后比較兩個(gè)數(shù)組的值畦韭,誰(shuí)小疼蛾,誰(shuí)放在新數(shù)組前面
            //直到一個(gè)數(shù)組比較完畢
            while (i < length1 && j < length2)
            {
                if (arr1[i] <= arr2[j])
                {
                    arr[index] = arr1[i];
                    i++;
                    index++;
                }
                else
                {
                    arr[index] = arr2[j];
                    j++;
                    index++;

                }

            }
            //將還沒(méi)有比較的數(shù)依次放在新數(shù)組后面
            while (i < length1)
            {
                arr[index] = arr1[i];
                i++;
                index++;
            }

            while (j < length2)
            {
                arr[index] = arr2[j];
                j++;
                index++;
            }
            return arr;
        }

時(shí)間復(fù)雜度: 可以看到歸并運(yùn)行的次數(shù)為( length1+length2 )次,因此它的時(shí)間復(fù)雜度為:O(n)艺配。
空間復(fù)雜度: O( n ) 察郁。

歸并排序:

歸并排序正是利用了上述歸并的思路為核心的排序方法。假設(shè)這里有一個(gè)長(zhǎng)度為1的數(shù)組转唉,那么無(wú)論如何他就是一個(gè)有序數(shù)組皮钠。歸并排序就是不斷分解數(shù)組,直到數(shù)組長(zhǎng)度為1赠法,然后不斷歸并鳞芙,最后形成一個(gè)有序的數(shù)組。這種思路就是歸并排序的遞歸實(shí)現(xiàn)的思路期虾。

演示動(dòng)畫如下:


merge5.gif

實(shí)現(xiàn)方式有兩種:遞歸和非遞歸。

遞歸方式就是不斷拆分?jǐn)?shù)組驯嘱,直到數(shù)組長(zhǎng)度為1镶苞,然后不斷歸并。

代碼如下:

      public static void MergeSort(int[] arr)
        {
            int length = arr.Length;
            if (length<2)
            {
                return;
            }
            MegerSort(arr, 0, length-1);
        }

        public static void MergeSort(int[] arr,int left,int right)
        {
            //數(shù)組一分為2鞠评,不斷拆分茂蚓,直到數(shù)組長(zhǎng)度為1,直接返回
            if (left>= right)
            {
                return;
            }
            int mid = left+(right - left) / 2;
            MergeSort(arr, left, mid);
            MergeSort(arr, mid+1, right);

            //按mid將數(shù)組分組剃幌,然后將兩組數(shù)據(jù)歸并為1組
            int[] arr2 = new int[right - left+1];
            int index = 0;
            int i = left;
            int j = mid + 1;

            while (i <= mid&& j <= right)
            {
                if (arr[i] <= arr[j])
                {
                    arr2[index] = arr[i];
                    i++;
                    index++;
                }
                else
                {
                    arr2[index] = arr[j];
                    j++;
                    index++;

                }
            }

            while (i <= mid)
            {
                arr2[index] = arr[i];
                i++;
                index++;
            }

            while (j <= right)
            {
                arr2[index] = arr[j];
                j++;
                index++;
            }


            for (int n = 0; n < index; n++)
            {
                arr[left + n] = arr2[n];
            }
        }

非遞歸方式就是利用循環(huán)聋涨,從按長(zhǎng)度為1分組,然后歸并负乡,不斷翻倍數(shù)組長(zhǎng)度牍白,進(jìn)行歸并。

代碼如下:

       public static void MergeSort2(int[] arr)
        {
            int length = arr.Length;
            if (length<2)
            {
                return;
            }

            //按gap對(duì)數(shù)組進(jìn)行分組抖棘,并在組內(nèi)進(jìn)行歸并
            int gap = 1;
            while (gap<=length)
            {
                int i = 0;
                int left = i * (gap * 2);
                while (left< length)
                {                  
                    int right = (i + 1) * (gap * 2) - 1;
                    //數(shù)組數(shù)組越界的情況
                    if (right >= length)
                    {
                        right = length - 1;
                    }
                    MergeSort2(arr, left, right);
                    i++;
                    left = i * (gap * 2);
                }
                gap *= 2;
            }

        }

        //將數(shù)組分組為left-mid,mid+1-right兩組進(jìn)行歸并
        public static void MergeSort2(int[] arr,int left,int right)
        {
            if (right<= left)
            {
                return;
            }
            int mid = left + (right - left) / 2;
            int[] arr2 = new int[right - left + 1];
            int index = 0;
            int i = left;
            int j = mid + 1;

            while (i <= mid && j <= right)
            {
                if (arr[i] <= arr[j])
                {
                    arr2[index] = arr[i];
                    i++;
                    index++;
                }
                else
                {
                    arr2[index] = arr[j];
                    j++;
                    index++;

                }

            }

            while (i <= mid)
            {
                arr2[index] = arr[i];
                i++;
                index++;
            }

            while (j <= right)
            {
                arr2[index] = arr[j];
                j++;
                index++;
            }


            for (int n = 0; n < index; n++)
            {
                arr[left + n] = arr2[n];
            }
        }

時(shí)間復(fù)雜度:歸并一次的時(shí)間復(fù)雜度為O(n)茂腥,無(wú)論是遞歸,還是循環(huán)切省,都要執(zhí)行l(wèi)og2n次歸并最岗。因此復(fù)雜度為:O(nlog2n)
空間復(fù)雜度:O(n)。
穩(wěn)定性:穩(wěn)定排序朝捆。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末般渡,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌驯用,老刑警劉巖脸秽,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異晨汹,居然都是意外死亡豹储,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門淘这,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)剥扣,“玉大人,你說(shuō)我怎么就攤上這事铝穷∧魄樱” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵曙聂,是天一觀的道長(zhǎng)晦炊。 經(jīng)常有香客問(wèn)我,道長(zhǎng)宁脊,這世上最難降的妖魔是什么断国? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮榆苞,結(jié)果婚禮上稳衬,老公的妹妹穿的比我還像新娘。我一直安慰自己坐漏,他們只是感情好薄疚,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著赊琳,像睡著了一般街夭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上躏筏,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天板丽,我揣著相機(jī)與錄音,去河邊找鬼趁尼。 笑死檐什,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的弱卡。 我是一名探鬼主播乃正,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼婶博!你這毒婦竟也來(lái)了瓮具?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎名党,沒(méi)想到半個(gè)月后叹阔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡传睹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年耳幢,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片欧啤。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡睛藻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出邢隧,到底是詐尸還是另有隱情店印,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布倒慧,位于F島的核電站按摘,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏纫谅。R本人自食惡果不足惜炫贤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望付秕。 院中可真熱鬧兰珍,春花似錦、人聲如沸盹牧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)汰寓。三九已至,卻和暖如春苹粟,著一層夾襖步出監(jiān)牢的瞬間有滑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工嵌削, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留毛好,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓苛秕,卻偏偏與公主長(zhǎng)得像肌访,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子艇劫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

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

  • 一些概念 數(shù)據(jù)結(jié)構(gòu)就是研究數(shù)據(jù)的邏輯結(jié)構(gòu)和物理結(jié)構(gòu)以及它們之間相互關(guān)系吼驶,并對(duì)這種結(jié)構(gòu)定義相應(yīng)的運(yùn)算,而且確保經(jīng)過(guò)這...
    Winterfell_Z閱讀 5,654評(píng)論 0 13
  • 1 初級(jí)排序算法 排序算法關(guān)注的主要是重新排列數(shù)組元素,其中每個(gè)元素都有一個(gè)主鍵蟹演。排序算法是將所有元素主鍵按某種方...
    深度沉迷學(xué)習(xí)閱讀 1,391評(píng)論 0 1
  • 搞懂基本排序算法 上篇文章寫了關(guān)于 Java 內(nèi)部類的基本知識(shí)风钻,感興趣的朋友可以去看一下:搞懂 JAVA 內(nèi)部類;...
    醒著的碼者閱讀 1,169評(píng)論 3 4
  • 概述 排序有內(nèi)部排序和外部排序酒请,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序骡技,而外部排序是因排序的數(shù)據(jù)很大,一次不能容納全部...
    蟻前閱讀 5,164評(píng)論 0 52
  • 通過(guò)前面的知識(shí)羞反,我們已經(jīng)知道布朦,有序的數(shù)據(jù)在查找時(shí)有極大的性能提升。很多查找都基于有序數(shù)據(jù)苟弛,但并不是所有的結(jié)構(gòu)都能像...
    大大紙飛機(jī)閱讀 1,164評(píng)論 0 1