简述

!如果想直接看代码请直接移步文末!

归并是一种常见的操作,即将两个有序的数组归并成一个更大的有序数组。很快人们就根据这个操作发明了一种简单的递归排序算法:归并排序。归并排序最吸引人的性质是它能够保证将任意长度的为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]

java 两个有序数组合并成一个有序数组 java两个有序数组合并排序_合并排序


根据上图,我们可以将数组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]);
		}
	}
}

------------------------------------施工现场------------------------------------