歸併操作:即將兩個有序的陣列歸併成乙個更大的有序陣列。
歸併排序示意圖:
歸併排序最吸引人的性質是它能夠保證將任意長度為n的陣列排序所需時間和nlogn成正比;它的最主要缺點則是它所需的額外空間和n成正比。
原地歸併的抽象方法
它將涉及的所有元素複製到乙個輔助陣列中,再把歸併的結果放回原陣列中。
merge方法在歸併時進行了4個條件判斷:
過程如圖:
自頂向下的歸併排序(化整為零地解決問題)
下面演算法應用了分治思想,實現了一種遞迴歸併,即如果它能將兩個子陣列排序,它就能夠通過歸併兩個子陣列來將整個陣列排序。
package section2_1;
public
class
mergetopdown
private
static
void
show
(comparable[
] a)
system.out.
println()
;}public
static
boolean
issorted
(comparable[
] a)
return
true;}
public
static
void
merge
(comparable[
] a,
int lo,
int mid,
int hi)
for(
int k = lo;k <= hi;k++)}
public
static
void
sort
(comparable[
] a)
private
static
void
sort
(comparable[
] a,
int lo,
int hi)
public
static
void
main
(string[
] args)
;sort
(a);
assert
issorted
(a);
show
(a);
}}
過程如圖:
對於長度為n的任意陣列,自頂向下的歸併排序需要的時間與nlgn成正比。它表明我們只需要比遍歷整個陣列多個對數因子的時間就能將乙個龐大的陣列排序。可以用歸併排序處理數百萬甚至更大規模的陣列,這是插入排序或者選擇排序做不到的。歸併排序的主要缺點是輔助陣列所使用的額外空間和n的大小成正比。
改進:對小規模子陣列使用插入排序
用不同的方法處理小規模問題能改進大多數遞迴演算法的效能,因為遞迴會使小規模問題中方法的呼叫過於頻繁。對於排序來說,在小陣列上插入排序或選擇排序比歸併排序更快。使用插入排序處理小規模的子陣列一般可以將歸併排序的執行時間縮短10%~15%。
自底向上的歸併排序(循序漸近地解決問題)
實現歸併排序的另一種方法是先歸併那些微型陣列,然後再成對歸併得到的子陣列,如此這般,直到我們將整個陣列歸併在一起。這種實現方法比標準遞迴方法所需要的**量更少。
過程如圖:
}}自底向上的歸併排序會多次遍歷整個陣列,根據陣列大小進行兩兩歸併。子陣列的大小sz的初始值為1,每次加倍。最後乙個子陣列的大小只有在陣列大小是sz的偶數倍的時候才會等於sz(否則它會比sz小)。
對於長度為n的任意陣列,自底向上的歸併排序需要1/2nlgn至nlgn次比較,最多訪問陣列6nlgn次。
自底向上的歸併排序比較適合用鍊錶組織的資料。這種方法只需要重新組織鍊錶鏈結就能將鍊錶原地排序(不需要建立任何新的鍊錶結點)。
排序演算法的複雜度
沒有任何基於比較的演算法能夠保證使用少於lg(n!)~nlgn次比較將長度為n的陣列排序。
這個結論告訴了我們在設計排序演算法的時候能夠達到的最佳效果。
歸併排序是一種漸近最優的基於比較排序的演算法。
準確的上界為軟體工程師保證效能提公升了空間。準確的下界可以為我們節省很多時間,避免因不可能的效能改進而投入資源。
歸併排序的最優性並不是結束,也不代表在實際應用中我們不會考慮其他的方法了:
alg4 排序 堆排序
堆排序可以分為兩個階段。在堆的構造階段中,我們將原始陣列重新組織安排進乙個堆中 然後在下沉排序階段,我們從堆中按遞減順序取出所有元素並得到排序結果。堆的構造 從右至左用sink 函式構造子堆。陣列的每個位置都已經是乙個子堆的根結點了,sink 對於這些子堆也適用。如果乙個結點的兩個子結點都已經是堆了...
演算法分析(4) 排序 歸併排序
3 自底向上的歸併排序 less和exch可以檢視上一章 演算法分析 3 簡單排序總結 選擇,插入,希爾含 comparable介面 歸併採用分治法 divide and conquer 的乙個非常典型的應用。將已有序的子串行合併,得到完全有序的序列 即先使每個子串行有序,再使子串行段間有序。若將兩...
19 排序 歸併排序
將已有序的子串行合併,得到有完全有序的序列 leftstart 左邊陣列的起始位置,rightstart 右邊陣列的起始位置,rightend 右邊陣列的結束位置 void merge elementtype a,elementtype tmpa,int leftstart,int rightsta...