演算法導論 歸併排序

2021-06-18 14:03:27 字數 2981 閱讀 5544

演算法的設計有很多思想,之前的插入排序使用的是增量的方法,即在排好的子陣列a中,將元素a[j]插入,形成新的子陣列a。

這次將實現另一種排序——歸併排序,歸併排序採用了「分治法」(divide-and-conquer),本篇中包含

分治法,也可以稱為分治策略:是將乙個大規模的問題(原問題)劃分成n個規模較小而結構與原問題相似的子問題,遞迴地解決這些子問題,然後再合併其結果,就得到原問題的解。

分治模式在每一層遞迴上都有三個步驟:

分解(divide):將原問題分解成一系列子問題

解決(conquer):遞迴地解決各子問題。若子問題足夠小,則直接求解

合併(combine):將子問題的結果合併成原問題的解

合併排序(merge sort)即參照了上述的模式:

分解:將n個元素分成各含n/2個元素的子串行

解決:用合併排序法對兩個子串行遞迴地排序

合併:合併兩個已排序的子串行以得到排序結果

若對子序列排序時,其長度為1時遞迴結束。因為當陣列中僅含有單個元素時,必定是有序的。

歸併排序主要分為遞迴與合併兩個部分,下面的偽**為合併部分,其中a是乙個陣列,p、q、r為下標,滿足

p≤q<r,a[p...q]與a[q+1...r]都是已排序好的,並合併成乙個已排序好的子陣列代替當前子陣列a[p...r]。

merge過程的時間代價為ɵ(n)其中n = r - p + 1為待合併元素個數。

歸併的遞迴過程,歸併的臨界點與陣列元素為1,因為陣列元素個數為1,代表陣列元素已排序。否則進行陣列一分為2的操作,下面為遞迴部分偽**

利用merge-sort( a, p, r )對子陣列a[p...r]進行排序。如果p≥r,則該子陣列中至多只有乙個元素,當然就是已排序的。否則,分解步驟就計算出乙個下標q,將a[p...r]分解為a[p...q]和a[q+1...r],各含[n/2]個元素。

/*程式執行完畢後,在done處,進行資源釋放

*/ goto done;

error:

printf ( "malloc has benn failed!\n" );

done:

if ( l != null && r != null ) }

void merge_sort ( int intarray, int head, int tail )

}int main ( void )

; int i = 0;

merge_sort ( a, 0, 7 );

for ( i = 0; i < 8; i++ )

while ( 1 );

}這裡有乙個待排序的陣列a= ( 5, 2, 4, 7, 1, 3, 2, 6 )

時間複雜度分析,設t(n)為乙個規模為n的問題的執行時間。如果問題的規模足夠小,如n≤c(c為常量),則得到它的直接解的時間為常量,寫作ɵ(1)。假設我們把原問題分解成a個子問題,每乙個的大小是原問題的1/b(對於合併排序,a和b都是2,但在許多分治法中,a≠b)。如果分解該問題和合併解的時間各為d(n)和c(n),則遞迴式為

worst-case

分析t(n)最壞情況下,合併排序n個數的執行時間,合併排序乙個元素的時間是個常量。當n>1時,將執行時間分解:

分解:這一步僅僅是計算出子陣列的中間位置,需要常量時間,因而d(n)= ɵ(1)

解決:遞迴地解兩個規模為n/2的子問題,時間為2t(n/2)

合併:在乙個含有n個元素的子陣列上,merge過程的執行時間為ɵ(n),則c(n) = ɵ (n)

當我們再合併排序演算法的分析中,將d(n)和c(n)相加時,我們是在將乙個ɵ(1)函式與另乙個ɵ(n)函式進行相加。相加的和是n的乙個線性函式,即ɵ(n)。將它與「解決」步驟中所得的2t(n/2)相加,即得到合併排序的最壞情況執行時間t(n)的遞迴表示

根據主定理(master theorem),它可以證明t(n)為ɵ(nlgn)。

這裡的lgn可以從樹的深度測出,因為是取2的n此冪,因為,樹的根節點為1,其他的分割是n/2;那麼可以簡單得出n = 1 * 2 * 2 * ... * 2,那麼樹的深度就是log_2 n,樹的高度為log_2 n + 1。

因為對數函式的增長速度比任何線性函式增長的都要慢,因此,當輸入規模足夠大時,合併排序要比插入排序要好(worst-case下合併排序為ɵ(nlgn),插入排序為ɵ(n2))

《演算法導論》

《網易公開課》——演算法導論

演算法導論 歸併排序

public class mergesort mergesort data,0,中間 mergesort data,中間,最後 merge data,0,最後 system.out.println 排序前 for int i 0 i9 i 10 0 system.out.println system...

演算法導論 歸併排序

歸併排序的步驟分為三個 將問題分解為更小的問題,然後解決小問題,將小問題合併為大問題的解。針對歸併排序的主要思想是 將乙個需要排序的陣列一分為二,然後將這兩部分進行單獨排序,然後將這兩個排好序的子數組合然後按照順序合併為大陣列。還有乙個就是邊界問題,將陣列無限的分下去知道最後的子陣列只剩乙個元素的時...

演算法導論 歸併排序

歸併排序是建立在歸併操作上的一種有效的排序演算法。該演算法是採用分治法 divide and conquer 的乙個非常典型的應用。歸併操作 merge 指的是將兩個已經排序的序列合併成乙個序列的操作。對兩個排序陣列合併成乙個有序陣列,這個很簡單 public int merge int a,int...