國立聯合大學
國立聯合大學 資訊管理學系資訊管理學系陳士杰老師陳士杰老師
Course 5
切割與征服
Divide-and-Conquer
▓ Outlines
本章重點
Divide-and-Conquer策略的描述
Binary Search
Merge Sort
Divide-and-Conquer 的技巧
Quick Sort
Strassen‘s 矩陣相乘演算法
何時不能使用 Divide-and-Conquer
Divide-and-conquer 是一種由上而下 由上而下 (top (top -down) - down) 的解題 方式.
它將一個問題切割 切割 (
dividesdivides) 成兩個或以上的較小問題。較小的問 題通常是原問題的實例。
如果較小的問題之解可以容易地獲得,那麼原問題的解可以藉由合 合 併較小問題的答案
併較小問題的答案獲得。
如果小問題還是太大以致於不易解決,則可以再被切割成更小的問 題直到切到夠小而易獲得結果為止。
▓ Divide-and-Conquer策略的描述與技巧
Def:
可將母問題切割成較小的問題 較小的問題 (切割),使用相同的解決程序 相同的解決程序加 以處理 (征服)。所有小問題的解可以成為母問題的最後解; 若有 必要,則再將每個小問題的處理結果加以合併,就可以得到最 後的答案。
{
由於使用相同的解決程序處理每個小問題,這一個程序就會被遞 迴呼叫,因此一個遞迴演算法則通常以一個副程式的型式出現,
內部包含一個解決程序與遞迴呼叫。
{
對於具有遞迴關係 遞迴關係的問題,或是一些採用遞迴定義的資料結構,
都適合採用Divide-and-Conquer演算法設計策略
最簡潔、易懂
效率差 (∵採用遞迴設計)
下列兩種情況是適合使用Divide-and-Conquer設計策略 (也 是遞迴演算法的適用時機):
問題本身具有遞迴關係 問題本身具有遞迴關係
{
母問題可被切割成較小的 “ 相同” 問題 相同
{
如: 階乘問題、費氏數問題、河內塔問題、快速排序問題、二 元搜尋問題…等
資料結構屬於遞迴定義 資料結構屬於遞迴定義
{
大量的Data Set,在切割後仍為一組具 “ 相同性質” 的Data Set 相同性質
{
如: 二元樹 (Binary Tree)、鏈結串列 (Link List)…等
Divide-and-Conquer使用時機
遞迴演算法則的設計
1. 找出問題的 終止條件. 終止條件
2. 找出問題本身的 遞迴關係 遞迴關係 ( ( 遞迴呼叫 遞迴呼叫 ) ) .
技巧:
思考遞迴呼叫需要哪些參數?
遞迴呼叫的傳回值為何?
遞迴呼叫的終止條件為何? 終止傳回何值?
Procedure Recursion_subroutine(Parameter);
{
if (終止條件 終止條件) then Return( );
else Recursion_subroutine(New_parameter Recursion_subroutine(New_parameter) ) ;
}
▓ Binary Search (二分搜尋)
實施前提:
檔案中記錄須事先由小到大 由小到大排序過
須由
Random (Random (或 或
Direct) accessDirect) access之機制支援 (e.g., Array)
觀念:
每次皆與Search範圍的中間記錄 中間記錄進行比較!!
while ( l ≤ u )
比較 (k, S[m])
case “=”: found, i = m, return i;
case “<”: uu= m-1;
case “>”: ll= m+1;
recurn 0;
小 大
⎥⎦ ⎥
⎢⎣ ⎢ +
= 2 middle
l u⎥⎦⎥
⎢⎣⎢ +
= 2 m l u
l m umiddle l m u
S
//找到了
//要找的資料在左半部 //要找的資料在右半部
分析
利用Time function T(n) = T(n/2) + O(1)
= T(n/2) + c
= (T(n/4 + c)) + c = T(n/4) + 2c
= (T(n/8) + c) + 2c = T(n/8) +3c
= …
= T(n/n) + log
2n×c
= T(1) + c log
2n (T(1) = 1, c 為大於 0 的常數)
= 1 + c log
2n
∴ T(n) = O(log
2n)
二元搜尋法的步驟摘要如下。如果x與中間項相同則離開,
否則:
切割 切割 (Divide) (Divide) 該陣列成大約一半大小的兩個子陣列。.
{
如果x小於中間項 小於中間項,選擇左邊的子陣列 左邊的子陣列。如果x大於中間項 大於中間項,則選擇右 右 邊的子陣列
邊的子陣列。
藉由判斷x是否在該子陣列中來征服 征服 (Conquer; (Conquer; 或稱解決 solve) ) 該 子陣列。
{
除非該子陣列夠小,否則使用 遞迴來做這件事。 遞迴
由子陣列的解答來獲得 獲得 (Obtain) (Obtain) 該陣列的解答。
二元搜尋法是最簡單的一種Divide-and-conquer演算法。因
為原有問題的解答就是較小問題所解出的解答,所以沒有
輸出結果的合併。
觀念:
將兩個已排序過的記錄合併,而得到另一個排序好的記 錄。
可分為兩種類型:
Recursive (遞迴)
Iterative (迴圈, 非遞迴)
▓ Merge Sort (合併排序)
Recursive Merge Sort (遞迴合併排序)
將資料量 n 切成 n/2 與 n/2 兩半部,再各自Merge 兩半部 Sort,最後合併兩半部之排序結果即成。
切割資料量 n 的公式為:
[ ]: Run, 已排序好的檔案記錄 已排序好
Run的長度: Run中 記錄個數 記錄個數
⎥⎦ ⎥
⎢⎣ ⎢ + 2
high)
(low
Stack
第一層切割所有 資訊依序輸入 第二層切割所有
資訊依序輸入 第三層切割所有
資訊依序輸入 第四層切割所有
資訊依序輸入
Time-Complexity
Avg. / Worst / Best Case: O(n O(n log n) log n)
以Recursive Merge Sort角度:
[說明]:
時間函數: T(n) = T(n/2) + T(n/2) + c×n 時間複雜度求法:
{
{
遞迴樹 遞迴樹
步驟:
將原本問題照遞迴定義展開
計算每一層的Cost
加總每一層的Cost即為所求
{{
數學解法 數學解法
最後合併左右兩半部 合併左右兩半部所花時間
∵ 左、右半部排好之後,各只 剩一個Run,且兩半部各有 兩半部各有
n/2n/2的資料量,其最後一次合併時 的資料量 的比較次數 “最多 最多 ”為 n/2 + n/2
n/2 + n/2 -1-1次,即約 n-1 次 (slide 72)
∴時間的表示可為 c
c× ×
nn次(∵為 次 線性時間)) 線性時間
左半部遞迴 右半部遞迴
合併排序法包含了下列的步驟 :
切割 切割 (Divide) (Divide) 該陣列成為兩個具有
nn/2/2個項目的子陣列。
征服 征服 (Conquer; 或稱解決solve (Conquer )每一個子陣列。 )
{
除非該子陣列夠小,否則使用 遞迴來做這件事。 遞迴
合併 合併 (Combine) (Combine) 所有子陣列的所有解答,以獲得主陣列的解答。
Divide-and-conquer 的設計策略包含下列的步驟:
切割 切割 (Divide) (Divide) 一個較大的問題以成為一個或多個較小的問題。
征服 征服 (Conquer ; 或稱解決solve (Conquer ) ) 每一個較小的問題。
{
除非問題已經足夠的小,否則使用遞迴 遞迴來解決。
如果需要, 將所有小問題的解答加以合併 如果需要 合併(combine) (combine) ,以獲得原 始問題的解答。
{
需要合併的問題: Merge sort
{
不需要合併的問題: Binary search
▓ Divide-and-Conquer 技巧
▓ Quick Sort (快速排序)
Avg. case 下,排序最快的algo.
Def:
將大且複雜的問題 切成許多獨立的小問題,再加以解決各小問題 切成許多獨立的小問題 後,即可求出問題的Solution。
此即 “
Divide-Divide-andand--ConquerConquer” (切割並征服)的解題策略。
觀念:
將第一筆記錄視為Pivot Key (樞紐鍵 (P.K.) ,或稱Control Key),在 Pass 1 (第一回合) 後,可將P.K.置於 “最正確” 的位置上。
Ex:
(經過Pass 1)
>
把P.K.擺在正確的位置 >為切割 切割的概念 (∴可使用 遞迴) 遞迴
P.K.
P.K.
R
iR
j, R
i.key ≤ P.K. 且 R
j.key ≥ P.K.
多顆CPU時的運算過程:
Time-Complexity
Best Case: O(n O(n log n) log n)
P.K.之最正確位置 恰好將資料量 恰好將資料量 均分成二等份 均分成二等份
{
以Multiprocessor來看,2個CPU的工作量相等,工作可同時做 完,沒有誰等誰的問題
[說明]:
時間函數: T(n) = c×n + T(n/2) + T(n/2) 時間複雜度求法:
{{
遞迴樹 遞迴樹
步驟:
將原本問題照遞迴定義展開
計算每一層的Cost
加總每一層的Cost即為所求
{{
數學解法 數學解法
變數
i 與 j 最多花 n 個執行時間找記錄
(即: 決定P.K.最正確位置所花時間
)左半部 右半部
Worst Case: O(n O(n
22) )
當輸入資料是由大到小 由大到小或 或由小到大 由小到大排好 排好時 ( ( 切割毫無用處 切割毫無用處 ) )
[說明]:
或
P.K.
P.K.
輸入資料: 輸入資料
:小 大
輸入資料: 輸入資料
:大 小
P.K.
[0筆[0
筆
]] [ n-[ n-11筆筆
]]P.K.
[0筆[0
筆
]] [ n[ n--11
筆 筆
]] Pass 1Pass 1
Pass 1 Pass 1
Average Case: O(n O(n log n) log n)
[說明]:
⇒ [T(s) T(n s)] cn , T(0) = 0
n T(n) 1
n
1 s
+
− +
= ∑
=
P.K.
S筆 (n-S)筆
▓ Strassen's Matrix Multiplication Algorithm
矩陣乘法問題 (Matrix Multiplication Problem):
給定兩個方陣A, B,其Size均為n×n,其中 n=2 n=2
kk。如果n不是2的冪次 方,則可以增加額外的列與行 增加額外的列與行,但是補上的元素都是零 零:
{
若矩陣是扁的,則可以在該矩陣下方補上數 列的0,使之成為方陣 列
{
若矩陣是窄的,則可以在該矩陣右方補上數 行的0,使之成為方陣 行
欲求C = A × B,傳統的矩陣乘法:
c
11= a
11×b
11+a
12×b
21c
12= a
11×b
12+a
12×b
22c
21= a
21×b
11+a
22×b
21c
22= a
21×b
12+a
22×b
22
將矩陣乘法問題放大來看:
C
11=
A11×B
11+
AA1212× ×
BB2121C
12=
AA1111× ×
BB1212+
AA1212× ×
BB2222C
21=
AA2121× ×
BB1111+
AA2222× ×
BB2121C
22=
AA2121× ×
BB1212+
AA2222× ×
BB2222
遞迴方程式為: T(n) = 8T(n/2) +cn
2
由支配理論可以得知該遞迴方程式最後可以得到 θ θ (n (n
33) )
C
ij, A
ij, B
ij皆為子矩陣 子矩陣,即可
用 遞迴切割的方式來將此矩 遞迴切割
陣切割成數個小矩陣。
該演算法的時間複雜度為
O(nO(n33)),乘法運算比加法運算要來得多。
前例的乘法有8個,加法有4個。
然而,就系統執行的角度來說,乘法運算的複雜度遠超過加法運算,
因此該演算法在實際執行的速度會更慢。
在1969年, Strassen 發 表了一個時間複雜度 較三次方演算法為佳 (time complexity is
better than cubic)的演 算法。
Strassen的方法需要 7 7
次乘法和 次乘法和 18 18 次的加 次的加 / / 減 減
法 法
遞迴方程式為: T(n) = 7T(n/2) +cn
2
由支配理論可以得知該遞迴方程式最後可以得到θ(n
lg7)
在下列兩種情況,我們應免使用 Divide-and- conquer:
1) 一個大小為n的個體被分成兩個或更多個大小為接近n 的個體.
2) 一個大小為n的個體被分成n個大小為n/c的個體,其中 c為常數.
▓ 何時不能使用 Divide-and-Conquer
有時,某些問題隨輸入範例的大小成指數成長是 無法避免的。雖然此時Divide-and-conquer無法獲 致良好的執行效率,但仍可採用。
河內塔問題每呼叫一次就需搬動圓盤一次,當圓盤的個 數 n 是64時,總共需要搬動圓盤 2
64-1次,因此演算法 的複雜度等級 (order) 是 O(2
n)
{
即: 河內塔問題的圓盤搬動次序是與 n 成 指數關係 指數關係