【Java】Java實現歸併排序(合併排序)

簡述

!如果想直接看代碼請直接移步文末!

歸併是一種常見的操作,即將兩個有序的數組歸併成一個更大的有序數組。很快人們就根據這個操作發明了一種簡單的遞歸排序算法:歸併排序。歸併排序最吸引人的性質是它能夠保證將任意長度的爲N的數組排序所需的時間和N*logN成正比;它的主要缺點則是他所需的額外空間和N成正比。

!歸併排序中用到了遞歸的思想,掌握遞歸的思想對於理解歸併排序十分重要!

自頂向下的歸併排序

先假設有兩個已經有序的數組,比如
{1,2,5,6}和{2,3,5,8}
那應該怎樣把這兩個數組合併成爲一個有序的數組呢?
排序過程如下,分析過程在代碼後

	public static void merge(Comparable[] a, int low, int mid, int high) {
		//將a[low...mid]歸併
		int i = low, j = mid+1;
		
		for (int k=low; k<=high; k++) {//將a[low...high]複製到aux[low...high]中
			aux[k] = a[k];
		}
		
		for (int k = low; k <= high; k++) {
			if (i > mid)					
				a[k] = aux[j++];
			else if (j > high) 				
				a[k] = aux[i++]; 
			else if (less(aux[j], aux[i]))
				a[k] = aux[j++];
			else
				a[k] = aux[i++];
		}
	}
	
	//用於比較大小的方法
	public static boolean less(Comparable v, Comparable w) {
		return v.compareTo(w) < 0;
	}

我們使用了一個輔助數組aux[],先將兩個需要排序的有序數組放到數組a[]中,然後把a[]的元素複製到aux[]中,然後再從aux[]中歸併產生的有序數組複製回到a[]中

其中主要方法爲merge(),外加一個比較大小的compare方法。在merge()中的歸併部分(第二個for循環),進行了四個判斷:
if (前半部分用完) 取後半邊元素
else if (後半部分用完) 取前半邊元素
else if (後半部分當前元素小於前半部分當前元素) 取後半部分元素
else if(前半部分當前元素小於後半部分當前元素)取前半部分元素

我們需要記住merge()方法的具體作用:merge()可以把兩個有序的數組合併成一個有序的數組

merge()方法只是歸併排序中的一部分但也是很重要的一部分,現在我們着眼於整個歸併排序。歸併排序的核心思想是分治思想。緝拿略來說:如果他能夠將兩個子數組排序,則他就能夠通過歸併兩個子數組來將整個數組排序

說起來還是太抽象了,我們看圖,假設我們有一個有8個元素的數組a[],它的8個元素分別是a[0],a[1]…a[7]

在這裏插入圖片描述
根據上圖,我們可以將數組a[]分割成若干個只有兩個元素的子數組。而merge()則可以將兩個有序的數組合成一個有序的數組。只有兩個元素的子數組直接對比兩個元素就可以使其有序。
我們對最小子數組a[0],a[1]和a[1],a[2]使用merge()方法後,可以得到一個有序的次級數組,而這個有序的次級子數組又和另外的次級子數組merge()合併成了有序的一個次2級子數組。如此往復,等到到達最頂層的時候,數組就已經排序完畢了。



這樣看來,merge()方法已經有了,還差一個將數組切割成最小子數組的方法。請看下面代碼(該代碼爲完整的歸併排序代碼)。尾部有排序的方法調用的軌跡,不瞭解的可以參考下

package MergeSort;

public class Exp1 {
	
	private static Comparable[] aux; //歸併所需的輔助數組
	
	public static void sort(Comparable[] a) {
		aux = new Comparable[a.length];
		sort(a, 0, a.length-1);
	}
	
	private static void sort(Comparable[] 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 boolean less(Comparable v, Comparable w) {
		return v.compareTo(w) < 0;
	}
	
	public static void merge(Comparable[] a, int low, int mid, int high) {
		//將a[low...mid]歸併
		int i = low, j = mid+1;
		
		for (int k=low; k<=high; k++) {//將a[low...high]複製到aux[low...high]中
			aux[k] = a[k];
		}
		
		for (int k = low; k <= high; k++) {
			if (i > mid)					
				a[k] = aux[j++];
			else if (j > high) 				
				a[k] = aux[i++]; 
			else if (less(aux[j], aux[i]))
				a[k] = aux[j++];
			else
				a[k] = aux[i++];
		}
	}
	
	
	//示例
	public static void main(String[] args) {
		Comparable[] a = {"M","E","R","G","E","S","O","R","T"};
		sort(a);
		//打印數組
		for (int i=0; i<a.length; i++) {
			System.out.println(a[i]);
		}
	}
}

------------------------------------施工現場-------------------------------------

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