1. 程式人生 > >歸併排序(Java實現)

歸併排序(Java實現)

歸併排序先遞迴地將陣列分成兩半分別排序,然後將結果歸併起來,遵循分冶模式:

  • 分解:分解待排序的n個元素的序列成各具n/2個元素的兩個子序列。
  • 解決:使用歸併排序遞迴地排列兩個子序列。
  • 合併:合併兩個已排序的子序列(歸併排序的關鍵步驟)。 時間複雜度為O(NlogN),空間複雜度O(N),穩定的排序(如果一個排序演算法能夠保留陣列中重複元素的相對位置則被稱為是穩定的)。 經數學證明,所有基於比較的排序演算法的時間複雜度的下界為O(NlogN)。 java.util.Arrays.sort()對基本資料型別使用三向切分的快速排序,對引用型別使用歸併排序。
public class Merge {
	private static int[] temp;
	
	/**
	 * 先將所有元素複製到temp[]中,然後再歸併回a[]。
	 * 當左半邊比較完元素或者右半邊的當前元素小於左半邊時,取右半邊的元素;
	 * 當右半邊比較完元素或者左半邊的當前元素小於右半邊時,取左半邊的元素。
	 */
	public static void merge(int[] a, int low, int mid, int high){
		//將a[low...mid]和a[mid+1...high]歸併
		int i = low;
		int j = mid + 1;
		
		for(int k = low; k <= high; k++){
			temp[k] = a[k];
		}
		for(int k = low; k <= high; k++){
			if(i > mid){
				a[k] = temp[j++];
			}else if(j > high){
				a[k] = temp[i++];
			}else if(temp[i] > temp[j]){
				a[k] = temp[j++];
			}else{
				a[k] = temp[i++];
			}
		}
	}
	public static void sort(int[] a){
		temp = new int[a.length];
		sort(a, 0, a.length - 1);
	}	
	/**
	 * 自頂向下的歸併排序
	 * 依次將子陣列排序,然後通過歸併兩個子陣列來將整個陣列排序。
	 */
	private static void sort(int[] a, int low, int high){
		//將陣列a[low...high]排序
		if(high <= low)
			return;
		int mid = low + (high - low) / 2;
		sort(a, low, mid);//將左半邊排序
		sort(a, mid + 1, high);//將右半邊排序
		merge(a, low, mid, high);//歸併結果
	}
	
	/**
	 * 自底向上的歸併排序:
	 * 先歸併那些微型陣列,然後再成對歸併得到子陣列,
	 * 如此這般,直到將整個陣列歸併在一起。
	 */
	public static void sort2(int[] a){
		int N = a.length;
		temp = new int[N];
		for(int i = 1; i < N; i = i + i){
			for(int low = 0; low < N - i; low += i + i){
				merge(a, low, low+i-1, Math.min(low+i+i-1, N-1));
			}
		}
	}
}