分治思想之排序演算法

2021-08-08 23:04:01 字數 3362 閱讀 8959

分而治之是設計高效演算法的乙個重要思想。本文主要總結一下分治思想在排序演算法中的運用。

排序在商業資料處理和現代科學計算中有著重要的地位,它能夠應用於事物處理、組合優化、天體物理學、分子動力學、語言學、基因組學、天氣預報和很多其它領域。——《演算法》。

發展至今,已經出現過很多的排序演算法。如選擇排序,插入排序,希爾排序,堆排序,歸併排序,快速排序。這裡主要總結下後面種,這種也是目前運用最廣和最高效的(雖然在某些特殊情況下,前面一些演算法的效率更加高,但這裡主要是針對一般情況下),這2種排序是分治思想的典型運用(分治思想也就是把大問題轉化為小問題,然後分別去解決,最後整體歸併)。

歸併,即將2個有序的陣列歸併成乙個更大的有序陣列。而不管是歸併排序還是快速排序都是基於歸併進行操作的。

1.自頂向下的歸併排序。

具體思想是先將左半邊排序,然後將右半邊排序,最後將排序好的結果歸併起來。

如下

private

static

void

sort(comparable a,int lo,int hi)

注意進行歸併操作時,需要使用乙個輔助陣列。首先把需要排序的所有元素放入到乙個輔助陣列中,歸併時需要進行4個判斷:如果左半邊的元素取完就取右半邊的元素;如果右半邊的元素取完就取左半邊的元素;如果右半邊的當前元素小於左半邊

的當前元素則取右半邊的元素;如果左半邊的當前元素大於右半邊的當前元素則取左半邊的元素。

最後看總體**

public

class

mergesort

private

static

void

sort(comparable a,int lo,int hi)

public

static

void

merge(comparable a,int lo,int mid,int hi)

// 對應上面所述的4個判斷

for (int k=lo;k<=hi;k++) else

if (j > hi) else

if (less(aux[j],aux[i])) else }}

// 元素v < w則返回true

public

static

boolean

less(comparable v,comparable w)

}

2.自底向上的歸併排序

當需要歸併的陣列較小時,可以考慮另一種歸併排序方法,自底向上發散。首先將陣列中的每個元素都想像成乙個大小為1的陣列,然後兩兩歸併。把歸併後的結果想象成大小為2的陣列,繼續進行四四歸併,接著八八歸併……以此類推,歸併完後的陣列就是已經排好序的陣列。

**如下

public

class

mergebu }}

public

static

void

merge(comparable a,int lo,int mid,int hi)

for (int k=lo;k<=hi;k++) else

if (j > hi) else

if (less(aux[j],aux[i])) else }}

public

static

boolean

less(comparable v,comparable w)

}

注意merge()方法中傳入的第4個引數,使用了math中的min方法,因為這裡涉及到邊界問題,對於乙個陣列我們不能確定它的大小是否剛好是2的多少次冪。

快速排序是被譽為二十世紀科學和工程領域的十大演算法之一,正因為它在處理不同資料方面平均情況下比其它排序演算法都要快得多,所以它也目前是應用最廣泛的排序演算法了,快速排序和歸併排序是互補的,快速排序是當2個子陣列都有序時,整個陣列也就有序了。

1.基本的快速排序

快速排序中,選定乙個切分元素v ,然後分遍歷左右兩邊的元素,如果v左邊的元素小於v,則進行遞增操作;繼續遍歷右邊,右邊元素大於v則進行遞減操作;其它情況下就把v左右兩邊的元素進行交換,直到遍歷完整個陣列。最後保證v左邊的元素都小於v,v右邊的元素都大於v。最終得到的切分元素v作為下一次進行排序的部分陣列的邊界,用同樣的方式進行遞迴排序。

**如下

public

class

quicksort

private

static

void

sort(comparable a,int lo,int hi)

// 切分方法

private

static

intpartition(comparable a,int lo,int hi)

while (less(v,a[--j]))

if (i >= j) break;

exch(a,i,j);

}exch(a,lo,j);

return j;

}private

static

boolean

less(comparable v,comparable w)

private

static

void

exch(comparable a,int i,int j)

}

2.三路快速排序

當需要進行排序的陣列出現大量重複的元素時,按理來說重複的元素應該不必進行排序了,但是之前那種快速排序還是會對它們進行切分,所以這裡快速排序有很大的改進空間。那就是把元素劃分為三部分,對應小於、等於、大於切分元素的部分。如下圖

如圖所示,這裡分別維護三個指標lt、i、gt。

如果a[i]小於v,則將a[lt]和a[i]進行交換,並且將i和lt都遞增;如果a[i]大於v,將a[i]和a[gt]進行交換,並且將gt遞減;如果a[i]等於v,將i遞增,然後繼續往後遍歷。

這樣一來就很好的解決了有大量相等元素時仍然進行切分並且重複遍歷的問題。

最後看下**

public

class

quick3waysort else

if (temp > 0) else

}sort(a,lo,lt-1);

sort(a,gt+1,hi);

}private

static

void

exch(comparable a,int i,int j)

}

最後,寫這篇東西是複習一下。建議有興趣的朋友去讀下robert sedgewick和kevin wayne的《演算法》。

演算法分析 分治思想之快速排序

優化乙個演算法的最根本的原理就是減少演算法的基本操作。分治法的設計思想是,將乙個難以直接解決的大問題,分割成一些規模較小的相同問題,以便各個擊破,分而治之。於是,在快速排序中,我們通過分割陣列的思路來將大問題分割成小規模的問題,與二分搜尋法類似的是,在二分法 中,我們需要進行的操作是搜尋,是在已經排...

演算法分析 分治思想之合併排序

根據分治策略,我們建立了合併排序演算法,合併排序演算法的基本思想是 將待排序元素分成大小大致相同的兩個子集合分別對兩 個子集合進行排序,最終將排好序的子集合合併成為所要求的排好序的集合。換句話說,將乙個陣列兩個兩個結合並排序,形成小範圍有序的新的陣列,再將新的陣列四個四個結合,在此形成新的陣列以此 ...

演算法筆記之演算法思想 分治演算法

分治演算法 divide and conquer 的核心思想其實就是四個字,分而治之 也就是將原問題劃分成 n 個規模較小,並且結構與原問題相似的子問題,遞迴地解決這些子問題,然後再合併其結果,就得到原問題的解。分治演算法是一種處理問題的思想,遞迴是一種程式設計技巧。實際上,分治演算法一般都比較適合...