1. 程式人生 > >演算法學習——歸併排序

演算法學習——歸併排序

歸併排序看起來比較難,程式碼量也比之前幾個排序多,研究歸併排序也確實用了挺長時間。

歸併排序中的“歸”是遞迴的意思,“並”是合併的意思,顧名思義,歸併就是先遞迴分開,再合起來,那麼歸併排序的思想就是將一個數據序列遞迴劃分為越來越小的半子表,再對半子表進行排序,最後再用遞迴的方法將排好序的半子表合併成為越來越大的有序序列,這也是分治思想在歸併排序中的體現。

歸併排序演算法的原理就是對於給定的一組記錄(假設一共有n個記錄),先將其以每兩個相鄰的長度為1的子序列進行劃分,得到n/2(向上取整)個長度為2或1的有序子序列,再將其兩兩合併,反覆執行此過程,直到得到一個有序序列。

所以歸併排序的主要思想就是先分後合,以陣列{36,21,25,42,38,27,16}舉例說明:

初始關鍵字:{36,21}  {25,42}  {38,27}  {16}

一趟歸併後:{21,36}  {25,42}  {27,38}  {16}

二趟歸併後:{21,25,36,42}  {16,27,38}

三趟歸併後:{16,21,25,27,38,42}

示例程式碼及結果如下:

package pp.suanfa;

/**
 * 歸併排序
 * 
 * @author xiaoGd
 *
 */

public class MergeSort {
	
	public static void Merge(int array[],int p,int q,int r)
	{
		int i,j,k,n1,n2;
		n1 = q-p+1;
		n2 = r-q;
		//一次將陣列拆分為兩個半子表
		int[] L = new int[n1];
		int[] R = new int[n2];
		for(i=0,k=p;i<n1;i++,k++)
		{
			L[i] = array[k];
		}
		for(i=0,k=q+1;i<n2;i++,k++)
		{
			R[i] = array[k];
		}
		//將兩個半子表進行排序放回到數組裡
		for(i=0,j=0,k=p;i<n1&&j<n2;k++)
		{
			if(L[i]>R[j])
			{
				array[k] = L[i];
				i++;
			}
			else
			{
				array[k] = R[j];
				j++;
			}
		}
		//若陣列長度為奇數,則將剩餘的半子表放回到數組裡
		if(i<n1)
		{
			for(j=i;j<n1;j++,k++)
			{
				array[k] = L[j];
			}
		}
		if(j<n2)
		{
			for(i=j;i<n2;i++,k++)
			{
				array[k] = R[i];
			}
		}
	}
	//遞迴實現拆分和重組
	public static void MergeSort(int array[],int p,int r)
	{
		if(p<r)
		{
			int q = (p+r)/2;
			MergeSort(array,p,q);
			MergeSort(array,q+1,r);
			Merge(array,p,q,r);
		}
	}
	//測試
	public static void main(String[] args) {
		int i = 0;
		int[] a = {5,6,4,7,9,1,3,8,2};
		int len = a.length;
		MergeSort(a,0,len-1);
		for(i=0;i<len;i++)
		{
			System.out.print(a[i]+" ");
		}
	}
}