有時候,你可能會遇到使用任何已知的演算法都無法解決的問題,這種時候,我們就可以試試分治法的思路。
分治法的基本思想很簡單,顧名思義,就是將乙個大問題分解為若干個子問題,然後我們逐一地解決這些子問題,將所有子問題解決完畢,也就將整體的大問題解決完畢了。
分治法的精髓:
分--將問題分解為規模更小的子問題;
治--將這些規模更小的子問題逐個擊破;
合--將已解決的子問題合併,最終得出「母」問題的解;
分治法的思路在具體操作時主要包括以下兩個步驟:
找出基線條件,這種條件必須盡可能簡單。
確定如何縮小問題的規模,然後不斷將問題分解(或者說縮小規模),直到符合基線條件。
舉個例子。給定乙個陣列,我們需要將該陣列的所有數字相加並返回結果。陣列如下所示:
2, 4, 6, 8
使用迴圈可以很容易地完成該任務:
def sum(arr):
total = 0
for x in arr:
total += x
return total
但是,分治法的思想是使用遞迴來完成該任務。通過遞迴的基線條件,我們將這個陣列數字累加的任務劃分成子問題,具體步驟如下:
第一步:找出基線條件。最簡單的陣列是什麼樣的呢?當然,如果陣列不包含任何元素或者只包含乙個元素,該陣列就是最簡單的了,計算該陣列的總和也就非常容易了。
所以,基線條件就是陣列不包含任何元素或者陣列只包含乙個元素。在不包含任何元素的情況下,陣列總和為0,而在只包含乙個元素的情況下,陣列總和即為該元素的數值。
第二步:每次遞迴呼叫都必須離空陣列更近一步。如何縮小問題規模呢?看下面的步驟:
首先,我們計算總和需要這樣做:
sum(2,4,6,8)=2+4+6+8=20
這種計算與下面的計算版本等效:
2+sum(4,6,8)=2+(4+6+8)= 2+18=20
在這裡呢,我們首先把第乙個元素2提取出來,然後計算剩下三個元素的總和為18,再把2和18相加同樣可以獲得結果20.
其次呢,對於後面三個數相加的結果,我們依然沿用該思路,我們首先把4提取出來,效果如下所示:
sum(4,6,8)=4+sum(6,8) =4+(6+8)=4+14=18
對於上面的計算式子,我們依然還是要對後面的兩個數字相加進行分解,將6提取出來,效果如下所示:
sum(6,8) = 6+sum(8)=6+8=14
當提取到上式時,最後進行sum運算的只剩下乙個元素8,這剛好符合了基線條件!而且在一次次地提取元素的過程中,我們傳遞給sum操作的運算元組越來越短,這就縮小了問題的規模了!
具體計算總和的**如下所示:
def sum_recurve(list):
if list ==
return 0
return list[0] + sum_recurve(list[1:])
當list陣列內部為空時返回0,否則將第乙個元素提取出來,計算除第乙個元素之外的其他數字的總和,然後與第乙個元素相加,再返回結果。
特別注意:編寫涉及陣列的遞迴函式時,基線條件通常情況下都是陣列為空或只包含乙個元素。程式設計陷入困境時,可以檢查基線條件是否設定正確。
演算法 分治法
include function 列印int型陣列 parameter int型陣列,陣列的長度 void displayarray int a,int n printf n function 劃分由下標s開始到t終止的int陣列 parameter int型陣列,陣列的起始座標,陣列的終點座標 r...
基礎演算法 合併排序(分治法)
基礎演算法 合併排序演算法 分治法 的宗旨是將問題 分解 處理 歸併 將書中的偽 翻譯為c c 語言實現,大致可用兩個函式來解決問題,第乙個函式實現 治 也就是分解問題,處理問題 的步驟,另乙個函式通 過遞迴實現 分 合 的操作。實現 分 治 的函式實現如下 void merge int parra...
五大基礎演算法 分治法
1 定義 分治法的主題思想就是分而治之,也就是說把乙個大原問題變成兩個或者多個小問題解決,最後把小問題的解合併起來就是原問題的解。分 將原問題分解為多個小問題 治 將這些小問題逐個解決 合 將小問題解合併,就得出原問題的解 2.演算法實現 a 分治法的正規化 分解問題 把原問題分解為若干個與原問題性...