JAVA 實現 歸併排序算法

什麼是合併?

與不少有用的算法相似,合併排序基於這樣一個技巧:將 2 個大小爲 N/2 的已排序序列合併爲一個 N 元素已排序序列僅須要 N 次操做。這個方法叫作合併html

咱們用個簡單的例子來看看這是什麼意思:java

經過此圖你能夠看到,在 2 個 4元素序列裏你只須要迭代一次,就能構建最終的8元素已排序序列,由於兩個4元素序列已經排好序了:算法

  • 1) 在兩個序列中,比較當前元素(當前=頭一次出現的第一個)
  • 2) 而後取出最小的元素放進8元素序列中
  • 3) 找到(兩個)序列的下一個元素,(比較後)取出最小的
  • 重複一、二、3步驟,直到其中一個序列中的最後一個元素
  • 而後取出另外一個序列剩餘的元素放入8元素序列中。

這個方法之因此有效,是由於兩個4元素序列都已經排好序,你不須要再『回到』序列中查找比較。數據庫

                                   

  • 拆分階段,將序列分爲更小的序列合併排序是把問題拆分爲小問題,經過解決小問題來解決最初的問題(注:這種算法叫分治法,即『分而治之、各個擊破』)
  • 排序階段,把小的序列合在一塊兒(使用合併算法)來構成更大的序列

拆分階段

在拆分階段過程當中,使用3個步驟將序列分爲一元序列。步驟數量的值是 log(N) (由於 N=8, log(N)=3)。【譯者注:底數爲2,下文有說明】apache

我怎麼知道這個的?api

我是天才!一句話:數學。道理是每一步都把原序列的長度除以2,步驟數就是你能把原序列長度除以2的次數。這正好是對數的定義(在底數爲2時)。數組

排序階段

在排序階段,你從一元序列開始。在每個步驟中,你應用屢次合併操做,成本一共是 N=8 次運算。服務器

  • 第一步,4 次合併,每次成本是 2 次運算。
  • 第二步,2 次合併,每次成本是 4 次運算。
  • 第三步,1 次合併,成本是 8 次運算。

由於有 log(N) 個步驟,總體成本是 N*log(N) 次運算多線程

                 

合併排序的強大之處

爲何這個算法如此強大?框架

由於:

  • 你能夠更改算法,以便於節省內存空間,方法是不建立新的序列而是直接修改輸入序列。

               注:這種算法叫『原地算法』(in-place algorithm)

  • 你能夠更改算法,以便於同時使用磁盤空間和少許內存而避免巨量磁盤 I/O。方法是隻向內存中加載當前處理的部分。在僅僅100MB的內存緩衝區內排序一個幾個GB的表時,這是個很重要的技巧。

                注:這種算法叫『外部排序』(external sorting)。

  • 你能夠更改算法,以便於在 多處理器/多線程/多服務器 上運行。

                好比,分佈式合併排序是Hadoop(那個著名的大數據框架)的關鍵組件之一。

  • 這個算法能夠點石成金(事實如此!)

這個排序算法在大多數(若是不是所有的話)數據庫中使用,可是它並非惟一算法。若是你想多瞭解一些,你能夠看看 這篇論文,探討的是數據庫中經常使用排序算法的優點和劣勢。

算法代碼

我實現的歸併算法的java 代碼:

/**
	     * 歸併算法
	     * @param list
	     * @param first
	     * @param last
	     */
	    public static void mergeSort(int[] list, int first, int last){
	    	if(null == list || list.length < 0 || first == last){
	    		return;
	    	}
            //這個幾行代碼能夠省略 若是省略 那麼當只有2個元素的時候還須要調用此方法遞歸 
            //那麼其實只有一個元素看成mergeSort入參 其實沒什麼意義
            //加上這幾行僅僅是減小几回函數調用 對結果無影響 強迫症者 可刪除。
	    	if(last - first == 1){
	    		sort(list, first, (last + first)/2, last);
	    		return;
	    	}
	    	mergeSort(list, first, (last + first)/2);
	    	mergeSort(list, (last + first)/2 + 1, last);
	    	sort(list, first, (last + first)/2, last);
	    	
	    }
	    
        //這個方法是合併兩個有序數組 temp數組能夠不須要,直接對list 相應位置的元素操做便可
        //那麼這麼作合併元素就好像直接插入排序算法同樣,前半部分數組不動,後半部分數組比較插入
	    public static void sort(int[] list, int first, int mid, int last ){
	    	int[] temp = new int[last - first + 1];
	    	int i = 0;
	    	int j = 0;
	    	int index = 0;
			while(i < mid - first + 1 && j < last - mid){
				if(list[first + i] >= list[mid + 1 + j]){
					temp[index] = list[mid + 1 + j];
					j++;
					index++;
				} else {
					temp[index] = list[first + i];
					i++;
					index++;
				}
			}
			while(i < mid - first + 1){
				temp[index] = list[first + i];
				index++;
				i++;
			}
			while(j < last - mid){
				temp[index] = list[mid + 1 + j];
				index++;
				j++;
			}
			for(int k = first, n = 0; k <= last; k++, n++){
				list[k] = temp[n];
			}
			System.out.println(Arrays.toString(list));
	    		
	    }
相關文章
相關標籤/搜索