基本排序_歸併排序_Java實現

轉載請註明出處:http://blog.csdn.net/ljmingcom304/article/details/50378781
本文出自:【梁敬明的博客】

1.歸併排序

  歸併排序就是將一個序列拆分成單個元素,兩兩歸併爲新的有序序列,直到將子序列歸併爲一個完整的有序序列爲止。

歸併排序

  存在一個序列【4】【7】【8】【6】【5】【9】【3】【0】【2】【1】,從小到大進行排序。
  第一次歸併,將兩個元素歸併爲一個子序列,並將子序列按大小順序排列。
  第二次歸併,依次取出兩個子序列中較小的值進行排列,將兩個子序列歸併爲一個新的子序列,剩餘不足四個元素的子序列,歸爲一個子序列。
  第三次歸併,將每八個元素歸併爲一個子序列,不足八個元素的歸作一個序列。
  第四次歸併,將所有元素歸併爲一個完整的有序序列。

2.示例代碼

  對一個長度爲N的序列由小到大進行排列,序列需要進行歸併的次數爲log2N ,每次進行歸併的子序列步長爲2n1 ,子序列進行兩兩歸併時,依次取出較小的元素存入臨時序列中,再將臨時有序序列替換到原始序列中。

public class MergeSort {

    public static void main(String[] args) {
        int[] array = { 4, 7, 8, 6, 5, 9, 3, 0, 2, 1 };
        MergeSort.sort(array);
        System.out.println("排序後數組:" + Arrays.toString(array));
    }

    public static void sort(int[] a) {
        int i, j;
        int low, mid, high;// 數組索引的低、中、高
        int gap;// 數組索引間隔
        int time = (int) Math.ceil(Math.log(a.length) / Math.log(2));// 計算數組的合併次數
        for (i = 1; i <= time; i++) {
            gap = (int) (Math.pow(2, i) - 1);// 合併後相鄰子序列的步長
            // 遍歷每個合併後的數組
            for (j = 0; j + gap < a.length; j = j + gap + 1) {
                low = j;// 當前遍歷數組的索引最低值
                high = j + gap;// 當前遍歷數組的索引最大值
                mid = (int) Math.floor((high + low) / 2);// 當前遍歷數組的索引中間值
                merge(a, low, mid, high);
            }
            // 將剩下的數組進行歸併排序
            if (j + gap >= a.length) {
                low = j;// 當前遍歷數組的索引最低值
                high = a.length - 1;
                // 當前遍歷數組的索引中間值,j+gap代表理論上的最大索引
                mid = (int) Math.floor(((j + gap) + low) / 2);
                merge(a, low, mid, high);
            }
            System.out.println(Arrays.toString(a)+":"+i);
        }
    }

    /**
     * 數組合並後,low爲合併前第一段數組的最小角標,mid+1位合併前第二段數組的最小角標。
     * 同時low爲合併後數組的最小角標,high爲合併後數組的最大角標
     */
    private static void merge(int[] a, int low, int mid, int high) {
        if (low < high) {
            int[] temp = new int[high - low + 1];// 創建一個臨時數組
            int first = low;
            int second = mid + 1;

            // 掃描兩端序列,取最小值放入臨時數組中
            for (int i = 0; i < temp.length; i++) {
                if (first <= mid && second <= high) {
                    // 取出兩個數組中較小的數放入臨時數組中,其中一個數組中取出較小的數后角標後移,沒有取出較小數的數組角標不變
                    temp[i] = a[first] < a[second] ? a[first++] : a[second++];
                } else if (first <= mid) {// 若第一段數組沒有遍歷完,將剩餘的數添加到臨時數組中
                    temp[i] = a[first++];
                } else if (second <= high) {// 若第二段數組沒有遍歷完,將剩餘的數添加到臨時數組中
                    temp[i] = a[second++];
                }
            }

            // 將臨時數組中值替換到原始數組中
            for (int i = 0; i < temp.length; i++, low++) {
                a[low] = temp[i];
            }
        }
    }
}

3.算法分析

時間複雜度:
  歸併排序的序列需要進行log2n 次歸併,並且每次歸併的比較次數爲n ,因此時間複雜度爲O(nlog2n)
算法穩定性:
  相同元素之間不會發生位置交換,歸併排序是一種穩定的排序算法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章