排序算法系列(8)——歸并排序

接下來準備學習一下歸并排序
去別的blog看了一段,很多博客概括介紹歸并的時候是這樣子的:

基本理念:分治思想(divide and conquer)
主要用處:將兩個(或者多個 兩個就稱為<u>二路歸并</u>)已經排好序的序列合并排序
時間復雜度: O(n logn)

可以看出來這也是我們遇到的第三個n logn時間復雜度的排序了

歸并排序

基本思想:

以二路歸并為例子
其實說白了只有一句話
先分割再合并


  1. 給定一個數(shù)組array[n]
  2. 選取一個中間位置mid吧(只是一個標志,不要太care,注意inside,not outside) 需要排序的開始位置start,需要排序的結束位置end

需要有end和start的原因是因為,萬一我們只需要對array的[start,end]進行排序呢?
plus 至于是左閉右開還是都是閉,看你的end的取值咯,只要對應就好
另外(** start>mid>end**)

  1. 那么我們是不是就需要將array[start,mid]姑且稱之為array1和array[mid+1,end]姑且稱之為array2兩個數(shù)組排序后進行合并?
  2. 那么3. 提到的那兩個數(shù)組是不是按照剛才說的是將其排好序后才能merge(歸并)在一起?那么問題來了,這兩個數(shù)組要排序?
  3. 那么這個兩個數(shù)組(array1和array2)自己的問題就是需要排序
    那么是不是還要對于每個數(shù)組按照剛才2.的步驟來一遍?

遞歸 boom 問題解決了,那么還有一個問題,眾所周知,遞歸除了將步驟跳到前面做重復的工作(代碼中就是調用相同的函數(shù)) 還需要有一個臨界值,也就是什么時候表示我們不遞歸了? 直到遞歸到后面拆分的array數(shù)組的元素只有一個,是不是就開始回溯了?

over 大致思路就是這樣

下面看示例圖:注意不同顏色的箭頭,首先是(藍色箭頭一層層分下去)然后是(綠色箭頭一層層合并排序)

歸并排序示例.png

關注細節(jié):

  • 如何將兩個已經排好序的數(shù)組(比如是array1array2)合并成為一個數(shù)組呢?

思路很簡單,反正二者都是已經排好序的了,先確定一個臨時數(shù)組temp
(確保足夠長,要滿足 temp.length >= array1.length + array2.length)
然后就一個一個比較(假設是從小到大排序),假設i,j=0;
那么就是
①如果array1[i]>array2[j] 那么temp[k]=array1[i]; k++; i++; 否則temp[k] = array2[j]; k++; j++;
②然后接下來接著做①直到其中一個數(shù)組已經走到底了,那么就只需要
那么接下來就是將沒走到底的全接了temp后面

package mergeSort;

import java.util.Arrays;

/**
 * @author mengf 
 * 將兩個有序的數(shù)組合并為一個有序的數(shù)組的示例 
 * 默認兩個數(shù)組的排序從小到大
 */
public class Demo1 {
    public static void main(String[] args) {
        int[] array = merge(new int[] { 1, 3, 5, 7, 11 }, 
                            new int[] { 2, 4, 6, 8, 10, 12, 14, 15 });
        System.out.println(Arrays.toString(array));
    }

    public static int[] merge(int[] array1, int[] array2) {
        // i是array1的索引
        // j是array2的索引
        // k是新數(shù)組result的索引
        int i = 0, j = 0, k = 0;
        int length1 = array1.length;
        int length2 = array2.length;
        int[] result = new int[length1 + length2];
        while (i < length1 && j < length2) {
            // if (array1[i]<array2[j]) {
            //  result[k] = array1[i];
            //  i++;
            // }else {
            //  result[k] = array2[j];
            //  j++;
            // }
            // k++;
            // 上面注釋掉的這段代碼可以用一下一句來表示
            // 第一次發(fā)現(xiàn)三目運算符是如此的清爽
            result[k++] = array1[i] < array2[j] ? array1[i++] : array2[j++];
        }
        if (i < length1) {
            while (i < length1) {
                result[k++] = array1[i++];
            }
        } else if (j < length2) {
            while (j < length2) {
                result[k++] = array2[j++];
            }
        }
        return result;
    }
}

然后解決了思路的拆分問題(遞歸),也解決了將拼起來的兩個有序數(shù)組merge起來的問題,那么這個算法應該是沒有問題的了!
接下來我們開始上代碼!

package mergeSort;

import java.util.Arrays;

public class MergeSort {
    /**
     * 默認size是10 可以自行設定 擴容 一般設置為size是需要排序的數(shù)組的長度就好了
     */
    private static int temp[] = new int[10];

    public static void setBufferSize(int length) {
        temp = new int[length];
    }

    public static void main(String[] args) {
        int array[] = new int[]{
                10,9,8,7,6,5,4,3,2,1,0,-1,-10,-13,24
        };
        setBufferSize(array.length);
        //閉區(qū)間 所以length-1
        mergeSort(array, 0, array.length-1);
        System.out.println(Arrays.toString(array));
    }

    public static void mergeSort(int[] array, int start, int end) {
        if (start == end) {
            return ;
        }
        int mid = start + (end - start) / 2;
        mergeSort(array, start, mid);
        mergeSort(array, mid + 1, end);
        merge(array, start, mid, mid + 1, end);
        return;
    }

    private static void merge(int[] array,int start1,int end1,int start2,int end2) {
        int i = start1;
        int j = start2;
        int k = 0;
        
        while (i <= end1 && j <= end2) {
            temp[k++] = array[i] < array[j] ? array[i++]:array[j++];
        }
        while (i <= end1) {
            temp[k++] = array[i++];
        }
        while (j <= end2) {
            temp[k++] = array[j++];
        }
        //將temp的復制到對應的[start1,end1] [start2,end2]
        k = 0 ;
        for(int index = start1 ; index <= end1 ; index++){
            array[index] = temp[k++];
        }
        for(int index = start2 ; index <= end2 ; index++){
            array[index] = temp[k++];
        }
    }
}

測試的是成功的,但是不知道是不是最優(yōu)的做法,我只是按照思路自行寫了一遍,大家可以參考其他網站的寫法,畢竟這些常見排序算法的講解到處都是!
如果有更好的更優(yōu)雅的書寫方式,可以指出來,sharing is important!


我還是想吐槽啊,簡書為啥不能可以修改文字的顏色,不需要太多顏色,就紅色我也滿足了?。。?!我也不是想搞得花哨,只是覺得黑白還是太單調了,粗體有的時候也不能滿足我想要強調的心情。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容