數據結構與算法分析筆記(6)——歸併排序

歸併排序:要將一個數組排序,可以先(遞歸地)將它分成兩半分別排序,然後將結果歸併起來。歸併排序最吸引人的性質是它能夠保證將任意長度爲N的數組排序所需時間和NlogN成正比;它的主要缺點則是它所需的額外空間和N成正比。

基本思想:

  • 將數組一分爲(Divide array into two halves)
  • 對每部分進行遞歸式地排序(Recursively sort each half)
  • 合併兩個部分(Merge two halves)

演示:


1. 給出原數組a[],該數組的lo到mid,mid+1到hi的子數組是各自有序的

2. 將數組複製到輔助數組(auxiliary array)中,給兩部分的首元素分別以i和j的下標,給原數組首元素以k的下標


3. 比較i下標和j下標的元素,將較小值賦到k下標位置的元素內,然後對k和賦值的下標進行遞增;
    該演示裏j下標的元素比較小,於是將A賦到k的位置裏,再對k和j遞增,即j+1, k+1

4. 重複上述過程,直到比較完全部元素。

public class Merge {
	private static int[] aux;
	public static void sort(int[] a){
		aux = new int[a.length];
		sort(a,0,a.length-1);
	}
	private static void sort(int[] a,int lo,int hi){
		if(hi <=lo) return;
		int mid = lo + (hi-lo)/2;
		sort(a,lo,mid);//將左半邊排序
		sort(a,mid+1,hi);//將右半邊排序
		merge(a,lo,mid,hi);//歸併結果
	}
	public static void merge(int[] a,int lo,int mid,int hi){
		//將a[lo..mid]和a[mid+1..hi]歸併
		int i = lo, j = mid+1;
		for(int k= lo;k <= hi;k++)//將a[lo..hi]複製到aux[lo..hi]
			aux[k] = a[k];
		for(int k = lo;k <= hi;k++){
			if (i >mid)                    a[k] = aux[j++];
			else if (j > hi)               a[k] = aux[i++];
			else if (aux[j] < aux[i])      a[k] = aux[j++];
			else                           a[k] = aux[i++];
		}
		
	}
}

性能分析:

算法複雜度爲N*log(N)


優化:

問題:歸併排序需要根據數組大小N開闢額外的內存

 

原地算法(in-place Algorithm):佔用額外空間小於等於c log(N)的排序算法。

插入排序、選擇排序、希爾排序都屬於原地算法。歸併排序不屬於原地算法。Wiki參考

Kronrod在1969年發明了原地歸併排序(in-place merge),不過看起來好像不是那麼有用(Challenge for the bored)


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