算法系列之經常使用算法之一----分治算法

1、基本概念算法

在計算機科學中,分治法是一種很重要的算法。分治算法,字面上的解釋是「分而治之」,分治算法主要是三點:數組

1.將一個複雜的問題分紅兩個或更多的相同或類似的子問題,再把子問題分紅更小的子問題----「分」函數

2.將最後子問題能夠簡單的直接求解----「治」spa

3.將全部子問題的解合併起來就是原問題打得解----「合」blog

這三點是分治算法的主要特色,只要是符合這三個特色的問題均可以使用分治算法進行解決(注意用詞,是」用」,至於好很差就是另一回事了)排序

2、分治法的特徵遞歸

分治法所能解決的問題通常具備如下幾個特徵:內存

1) 該問題的規模縮小到必定的程度就能夠容易地解決開發

2) 該問題能夠分解爲若干個規模較小的相同問題,即該問題具備最優子結構性質。get

3) 利用該問題分解出的子問題的解能夠合併爲該問題的解;

4) 該問題所分解出的各個子問題是相互獨立的,即子問題之間不包含公共的子子問題。

第一條特徵是絕大多數問題均可以知足的,由於問題的計算複雜性通常是隨着問題規模的增長而增長;

第二條特徵是應用分治法的前提它也是大多數問題能夠知足的,此特徵反映了遞歸思想的應用;、

第三條特徵是關鍵,可否利用分治法徹底取決於問題是否具備第三條特徵,若是具有了第一條和第二條特徵,而不具有第三條特徵,則能夠考慮用貪心法或動態規劃法。

第四條特徵涉及到分治法的效率,若是各子問題是不獨立的則分治法要作許多沒必要要的工做,重複地解公共的子問題,此時雖然可用分治法,但通常用動態規劃法較好

3、爲何用分治法?怎麼正確使用分治法?

爲何用分治算法?咱們使用一種算法的緣由大部分狀況下都是爲了」快「,只有在少數狀況下,在程序已經足夠」快「的前提下,咱們纔會犧牲一部分的」快「,去保全一些開發因素(好比,程序的可維護性等等),那麼分治算法爲何快?咱們在用這個算法以前必需理解清楚這個問題。

分治算法的思想就是將一個問題規模比較大的問題劃分爲幾個相同邏輯性質(或者直接理解爲相似)的問題規模變小的子問題。咱們能夠從這裏入手。

舉個超級簡單的例子:

假若有一個存在n個元素的int型數組,咱們須要求該數組的和。

可能有些人想不想就是一個分治算法,將這個問題分爲兩個子問題,而後每一個子問題再分爲兩個子問題,當子問題的規模爲只有兩個數時進行相加。。。

然而,這種辦法是使用了分治算法,但是效率比直接遍歷一遍相加獲得的效率還要低的多.

爲何?由於分治算法自己不適合這種單次遍歷就能夠搞定的簡單問題。大家在閱讀一遍分治算法的思想:分治算法的思想就是將一個問題規模比較大的問題劃分爲幾個相同邏輯性質的問題規模變小的子問題,那麼這個定義存在一個隱含的前提,當問題規模比較大時,該問題解決起來要成倍的困難!

咱們能夠舉這樣一個簡單的例子:
咱們對一個存在n個元素的數組,使用簡單排序進行排序時:

當n=1時,無需比較

當n=2時,咱們須要1次比較

當n=3時,咱們須要3次比較

當n=4時,咱們須要6次比較

當n的數值比較大時,咱們須要比較的次數愈來愈多將會是一個巨大的數字。

而對於前面的求和的例子:
當n=1時,無需相加

當n=2時,咱們須要1次相加

當n=3時,咱們須要2次相加

當n=4時,咱們須要3次相加

仔細觀察這組數據,是否發現了什麼?

對於求和的例子來講,該問題的計算量與問題規模成正比,在相同的條件下,咱們根本無須使用分治算法,由於即便這個問題規模變大,他的解決問題的難易程度沒有絲毫改變,它所付出的,只不過是增大了問題規模後所必須付出的計算量,歸納起來就是線性增加的問題規模致使了線性增加的計算量。

而對於排序的例子,當問題規模變大時,計算量的增大是成冪次型增加的,歸納起來就是線性增加的問題規模致使了冪次型計算量的增加。使得問題規模大的問題解決起來更加困難。

綜合起來歸納,在問題規模與計算量成正比的算法中,分治算法不是最好的解法,而且有多是效率極其底下的算法。若是存在某個問題,線性增加的問題規模可能帶動計算量的非線性增加,而且符合分治算法的三個特徵,那麼分治算法是一個很不錯的選擇。

4、實例解析

1.二分查找

實例分析:也許有人看到這裏認爲二分查找算法與我前面的推論是矛盾的,但其實並不矛盾。不矛盾的緣由在於二分查找算法是存在前提條件的。二分查找的數組必須是有序狀態的,二分查找是根據它的規則特性人們找到的一種取巧的方法。對於一個無序的查找方法,個人結論依然有效。

代碼來一波:

image

 

2.棋盤覆蓋

問題描述: 一個2^k×2^k 個方格組成的棋盤中,恰有一個方格與其餘方格不一樣,稱該方格爲一特殊方格,且稱該棋盤爲一特殊棋盤。在棋盤覆蓋問題中,要用圖示的4種不一樣形態的L型骨牌覆蓋給定的特殊棋盤上除特殊方格之外的全部方格,且任何2個L型骨牌不得重疊覆蓋。

image

 

實例分析:每次都對分割後的四個小方塊進行判斷,判斷特殊方格是否在裏面。這裏的判斷的方法是每次先記錄下整個大方塊的左上角(top left coner)方格的行列座標,而後再與特殊方格座標進行比較,就能夠知道特殊方格是否在該塊中。若是特殊方塊在裏面,這直接遞歸下去求便可,若是不在,這根據分割的四個方塊的不一樣位置,把右下角、左下角、右上角或者左上角的方格標記爲特殊方塊,而後繼續遞歸。在遞歸函數裏,還要有一個變量s來記錄邊的方格數,每次對方塊進行劃分時,邊的方格數都會減半,這個變量是爲了方便判斷特殊方格的位置。其次還要有一個變nCount來記錄L型骨牌的數量。

代碼秀:

image

 

運行結果:

image

 

3.歸併排序/合併排序

實例分析:咳咳,大名鼎鼎的合併排序不用我多說吧。。。缺點是須要多佔一些內存充當緩衝區。。

上代碼:

image

 

4.快速排序

運行結果:有了合併排序怎麼能夠沒有快速排序咧

代碼:

image

相關文章
相關標籤/搜索