歸併排序(Selection Sort)-Java常見經典算法詳解

歸併排序(Merge Sort)算法簡介:

歸併排序是建立在歸併操作上的一種有效的排序算法,該算法是採用分治策略(Divide and Conquer)(分治法將問題分(divide)成一些小的問題然後遞歸求解,而治(conquer)的階段則將分的階段得到的各答案"修補"在一起,即分而治之)。的一個非常典型的應用。將已有序的子序列合併,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合併成一個有序表,稱爲二路歸併。歸併排序是一種穩定的排序方法。

歸併排序(Merge Sort)算法原理:

 可以看到這種結構很像一棵完全二叉樹,本文的歸併排序我們採用遞歸去實現(也可採用迭代的方式去實現)。階段可以理解爲就是遞歸拆分子序列的過程,遞歸深度爲log2(n)。

合併相鄰有序子序列:

再來看看階段,我們需要將兩個已經有序的子序列合併成一個有序序列,比如上圖中的最後一次合併,要將[4,5,7,8]和[1,2,3,6]兩個已經有序的子序列,合併爲最終序列[1,2,3,4,5,6,7,8],來看下實現步驟。

歸併排序(Merge Sort)代碼實現:

import java.util.Arrays;
public class Demo {
	    public static void main(String[] args){
	        int []arr = {9,8,7,6,5,4,3,2,1};
	        System.out.println("排序前:"+Arrays.toString(arr));
	        sort(arr);
	        System.out.println("排序前:"+Arrays.toString(arr));
	    }
	    public static void sort(int[] array){
	        int []temp = new int[array.length];//在排序前,先建好一個長度等於原數組長度的臨時數組,避免遞歸中頻繁開闢空間
	        sort(array,0,array.length-1,temp);
	    }
	    private static void sort(int[] array,int left,int right,int[] temp){
	        if(left<right){
	            int mid = (left+right)/2;
	            sort(array,left,mid,temp);//左邊歸併排序,使得左子序列有序
	            sort(array,mid+1,right,temp);//右邊歸併排序,使得右子序列有序
	            mergeSort(array,left,mid,right,temp);//將兩個有序子數組合並操作
	        }
	    }
	    private static void mergeSort(int[] array,int left,int mid,int right,int[] temp){
	        int i = left;//左序列指針
	        int j = mid+1;//右序列指針
	        int t = 0;//臨時數組指針
	        while (i<=mid && j<=right){
	            if(array[i]<=array[j]){
	                temp[t++] = array[i++];
	            }else {
	                temp[t++] = array[j++];
	            }
	        }
	        while(i<=mid){//將左邊剩餘元素填充進temp中
	            temp[t++] = array[i++];
	        }
	        while(j<=right){//將右序列剩餘元素填充進temp中
	            temp[t++] = array[j++];
	        }
	        t = 0;
	        //將temp中的元素全部拷貝到原數組中
	        while(left <= right){
	            array[left++] = temp[t++];
	        }
	   }
}

歸併排序(Merge Sort)的時間複雜度:

歸併排序中,分割序列所花費的時間不算在運行時間內(可以當作序列本來就是分割好的)。在合併兩個已排好序的子序列時,只需重複比較首位數據的大小,然後移動較小的數據,因此只需花費和兩個子序列的長度相應的運行時間。也就是說,完成一行歸併所需的運行時間取決於這-行的數據量。看一下上面的圖便能得知,無論哪一行都是n個數據,所以每行的運行時間都爲O(n)。
而將長度爲n的序列對半分割直到只有一個數據爲止時,可以分成log2(n)行,因此,總共有log2(n)行。也就是說,總的運行時間爲O(nlogn),這與前面講到的堆排序相同。

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