1. 程式人生 > >排序演算法Java實現——歸併排序

排序演算法Java實現——歸併排序

歸併排序(也可以叫合併排序),其實歸併排序的本質就是合併排序。

它是與插入排序、交換排序、選擇排序不同的一類排序方法,不同之處在於:

它要求:待排序序列是由若干個有序子序列組成。

那麼究竟什麼是歸併排序呢?歸併這個詞到底是什麼意思?

首先可以理解為就是合併,然後就是這個詞的由來,可以說歸併這個詞是個生造詞。 “歸併”由merge翻譯而來,所以歸併排序亦可以翻譯為:”合併排序“。因為此演算法的關鍵就在於合併。

一、基本思想

歸併排序是將兩個或兩個以上的有序序列合併成一個新的有序序列本篇文章介紹的就是歸併排序主要是將兩個有序資料序列合併成一個新的有序序列。

合併的方法是比較各子序列的第一個記錄的鍵值,最小的一個就是排序的第一個記錄的鍵值。取出這個記錄,繼續比較各子序列現有的第一個記錄的鍵值,便可以找出排序後的第二個鍵值。然後開始遞迴,最終得到排序結果。

所以歸併排序的基礎就是合併

1)有序序列的合併

歸併排序的核心是:兩個有序子序列的合併。

此演算法的執行時間為:O(n-h+1)。

這裡就不上C++程式碼了。

2)二路歸併排序

二路歸併排序是將兩個有序表合併成一個有序表的排序方法。

二路歸併排序是穩定的。

歸併排序演算法的時間複雜度為O(nlog2n)

二、程式碼

C++程式碼很簡單

...

JAVA程式碼挺複雜的

如下:

/*@(#)MergeSort.java   2017-4-25 
 * Copy Right 2017 Bank of Communications Co.Ltd.
 * All Copyright Reserved
 */

package com.sort.cn;

/**
 * TODO Document MergeSort
 * <p>
 * @version 1.0.0,2017-4-25
 * @author Singit
 * @since 1.0.0
 */
public class MergeSort {
	static int number=0;
    public static void main(String[] args) {
        int[] a = {24, 5, 98, 28, 99, 56, 34, 2 };
        printArray("排序前:",a);
        MergeSort(a);
        printArray("排序後:",a);
    }

    private static void printArray(String pre,int[] a) {
        System.out.print(pre+"\n");
        for(int i=0;i<a.length;i++)
            System.out.print(a[i]+"\t");    
        System.out.println();
    }

    private static void MergeSort(int[] a) {
        // TODO Auto-generated method stub
        System.out.println("開始排序");
        Sort(a, 0, a.length - 1);
    }

    private static void Sort(int[] a, int left, int right) {
        if(left>=right)
            return;
    
        int mid = (left + right) / 2;
        //二路歸併排序裡面有兩個Sort,多路歸併排序裡面寫多個Sort就可以了
        Sort(a, left, mid);
        Sort(a, mid + 1, right);
        merge(a, left, mid, right);

    }


    private static void merge(int[] a, int left, int mid, int right) {
    
        int[] tmp = new int[a.length];
        int r1 = mid + 1;
        int tIndex = left;
        int cIndex=left;
        // 逐個歸併
        while(left <=mid && r1 <= right) {
            if (a[left] <= a[r1]) 
                tmp[tIndex++] = a[left++];
            else
                tmp[tIndex++] = a[r1++];
        }
            // 將左邊剩餘的歸併
            while (left <=mid) {
                tmp[tIndex++] = a[left++];
            }
            // 將右邊剩餘的歸併
            while ( r1 <= right ) {
                tmp[tIndex++] = a[r1++];
            }
            
            
           
            
            System.out.println("第"+(++number)+"趟排序:\t");
            // TODO Auto-generated method stub
            //從臨時陣列拷貝到原陣列
             while(cIndex<=right){
                    a[cIndex]=tmp[cIndex];
                    //輸出中間歸併排序結果
                    System.out.print(a[cIndex]+"\t");
                    cIndex++;
                }
             System.out.println();
        }
}


輸出結果:
排序前:
24	5	98	28	99	56	34	2	
開始排序
第1趟排序:	
5	24	
第2趟排序:	
28	98	
第3趟排序:	
5	24	28	98	
第4趟排序:	
56	99	
第5趟排序:	
2	34	
第6趟排序:	
2	34	56	99	
第7趟排序:	
2	5	24	28	34	56	98	99	
排序後:
2	5	24	28	34	56	98	99	

三、總結

從以上程式碼可以看出,歸併排序演算法需要遞迴的進行分解、合併,每進行一次歸併排序需要呼叫一次merge()方法,每次執行merge()方法需要比較n次,

SO,

歸併排序演算法的時間複雜度為O(nlog2n)。

歸併排序的空間效率較差。因為它需要一個與原始序列同樣大小的輔助序列。

歸併排序是穩定的。