演算法與問題之分析
DESCRIPTION
演算法與問題之分析. 2. 演算法分析. 透過演算法的分析,我們可以判斷出一個演算法的好壞、改進它們 並且從一個問題的現有許多演算法中挑選出我們所需要的 在分析一個演算法的時候,我們主要關心的,是將來以程式語言來實作它並且執行該程式時所需要的記憶體量與時間 這其中我們尤其關心它所需要的時間. 演算法分析. 我們並不要求對於演算法的效率分析非常精準 一個“大概”的分析結果反而是比較受歡迎的 換句話說,演算法的分析只要八九不離十就可以了 差太多當然也不行!. 效率分析. 一個需要使用大量記憶體的程式它的執行時間通常也絕對不低 - PowerPoint PPT PresentationTRANSCRIPT
112/04/19 演算法 _ 第二章 1
演算法與問題之分析
2
112/04/19 演算法 _ 第二章 2-2
演算法分析 透過演算法的分析,我們可以判斷出一個演算
法的好壞、改進它們 並且從一個問題的現有許多演算法中挑選出我
們所需要的 在分析一個演算法的時候,我們主要關心的,
是將來以程式語言來實作它並且執行該程式時所需要的記憶體量與時間
這其中我們尤其關心它所需要的時間
112/04/19 演算法 _ 第二章 2-3
演算法分析 我們並不要求對於演算法的效率分析非
常精準 一個“大概”的分析結果反而是比較受
歡迎的 換句話說,演算法的分析只要八九不離
十就可以了 差太多當然也不行!
112/04/19 演算法 _ 第二章 2-4
效率分析 一個需要使用大量記憶體的程式它的執
行時間通常也絕對不低 因為每一個由程式所使用到的記憶體至
少都需要程式去讀 / 寫它 即使一個程式使用非常少的記憶體,它
也有可能需要非常高的計算時間 執行時間的分析才是關鍵之所在。
112/04/19 演算法 _ 第二章 2-5
效率分析策略 要分析一個演算法,我們可以針對該問
題或演算法的基本運算做分析,而忽略掉起始工作、迴圈控制、以及其他一些例行程序等
對許多演算法來說,這種基本運算有可能只在主要的迴圈中出現一次
112/04/19 演算法 _ 第二章 2-6
效率分析策略 幾個常見問題的基本運算 這些基本運算通常也構成演算法的執行瓶頸
挑選好基本運算而且整個執行的運算數目也大致跟基本運算的執行次數成正比,那麼我們就有了一個估算演算法效率的好準據
112/04/19 演算法 _ 第二章 2-7
效率分析策略 演算法複雜度 演算法的時間複雜度
112/04/19 演算法 _ 第二章 2-8
效率分析策略 我們必須有一個估算一個問題的輸入資料量
的準據
112/04/19 演算法 _ 第二章 2-9
效率分析策略 定義:一個演算法的時間複雜度是執行
該程式直到執行完畢所需要的計算機時間,並且將這個數目表示成這個演算法的輸入資料量的一個函數
例如, 2n, n2, n log n 等,其中 n 代表輸入資料的長度
112/04/19 演算法 _ 第二章 2-10
最好、最壞、與平均複雜度 假設我們的輸入資料量固定為 n
令 Dn 是針對一個問題的所有大小為 n 的可能輸入所成的集合
令 I 是 Dn 的一個元素,換句話說, I 代表一組大小為 n 的輸入資料
令 t(I) 是演算法處理輸入 I 所執行的基本運算數目。
112/04/19 演算法 _ 第二章 2-11
最好、最壞、與平均複雜度 B(n) = min{t(I)IDn}
演算法處理任何大小為 n 的輸入 I 所可能執行的最小基本運算數目-最好情況的複雜度
W(n) = max{t(I)IDn}
演算法處理任何大小為 n 的輸入 I 所可能執行的最大基本運算數目-最壞情況的複雜度
即時應用
112/04/19 演算法 _ 第二章 2-12
平均時間複雜度 令 p(I) 是輸入資料 I 的出現機率
定義該演算法所執行的平均運算量-平均時間複雜度,如下:
nDI
ItIpnA )()()(
112/04/19 演算法 _ 第二章 2-13
近似符號
f
)( f
)( f
)( fO
:成長速度至少跟 f 一樣快 的函數
:成長速度跟 f 一樣快 的函數
:成長速度不快於 f 的函數
112/04/19 演算法 _ 第二章 2-14
近似符號
112/04/19 演算法 _ 第二章 2-15
近似符號 當 n 2 時, 3n + 2 4n 成立,因此 3n
+ 2 = O(n)
當 n 100 時, 1000n2 + 100n – 6 1001n2 成立,因此 1000n2 + 100n - 6 = O(n2)
當 n 2 時, 10n2 + 4n + 2 10n4 成立,因此, 10n2 + 4n + 2 = O(n4)
112/04/19 演算法 _ 第二章 2-16
近似符號 當 n 1 時, 3n + 2 3n 成立,因此 3n
+ 2 = (n)
當 n 1 時, 10n2 + 4n + 2 n2 成立,因此 10n2 + 4n + 2 = (n2)
當 n 1 時, 6*2n + n2 2n 成立,因此 6*2n + n2 = (2n)
112/04/19 演算法 _ 第二章 2-17
近似符號 當 n 2 時, 3n + 2 3n 成立,而且當
n 2 時, 3n + 2 4n 成立,因此 c1 = 3, c2 = 4, n0 = 2, 且 3n + 2 = (n)
10n2 + 4n + 2 = (n2)
6*2n + n2 = (2n)
10*log n + 4 = (log n)
112/04/19 演算法 _ 第二章 2-18
常見的演算法複雜度
112/04/19 演算法 _ 第二章 2-19
常見的演算法複雜度
112/04/19 演算法 _ 第二章 2-20
常見的演算法複雜度 O(1) < O(log log n) < O(log n) < O(n) < O(n log n)
< O(na) < O(2n)
112/04/19 演算法 _ 第二章 2-21
一些常用到的性質
)()()(
)}(),(max{)(
gOfOgfO
gOfOgfO
112/04/19 演算法 _ 第二章 2-22
一些常用到的性質 一個根據 O(n3) 的演算法所編寫出的程
式是否一定執行得比一個根據 O(n) 的演算法所編寫出的程式慢?
不一定 ! 0.1n3 vs. 1000n
但是,只要 n 夠大,我們可以保證根據O(n) 的演算法所編寫出的程式一定跑得比較快
112/04/19 演算法 _ 第二章 2-23
因此 當輸入資料量很少( n 很小)時,我們
不見得要挑選複雜度最低的演算法 就以排序為例,如果 n 很大,那麼我們
當然要選用 O(n log n) 的快速排序法 但是,如果 n 很小,那麼我們選用 O(n
2) 的氣泡排序法就可以了
112/04/19 演算法 _ 第二章 2-24
複雜度分析範例 二元搜尋- a[1]…a[n]
令 left 和 right 分別表示我們要搜尋的序列之左端與右端
一開始 left = 1 而 right = n
令 middle = ( left + right )/2 為此序列的中端
112/04/19 演算法 _ 第二章 2-25
二元搜尋 把 a [middle] 和 x 做比較,我們可以
得到以下三種結果的一種: x < a [middle] :在這種情況下,將 right
設成 middle-1
x = a[middle] :在這種情況下,回傳 middle
x > a[middle] :在這種情況下,將 left 設成 middle+1
112/04/19 演算法 _ 第二章 2-26
二元搜尋
1 left := 1, right := n; 2 while(還有元素) // 如果 left right表示還有元素要比對 3 { 4 middle := (left + right)/2; 5 if (x < a[middle]) right := middle-1 ; 6 else if (x > a[middle]) left := middle+1 ; 7 else return middle ; 8 } 9 return -1; // 沒找到
112/04/19 演算法 _ 第二章 2-27
二元搜尋 B(n)=O(1)
W(n)=O(log n) T(n) = T(n/2) + O(1) = O(log n)
事實上,我們可以證明二元搜尋的的平均計算時間也是 O(log n)
112/04/19 演算法 _ 第二章 2-28
選擇排序
112/04/19 演算法 _ 第二章 2-29
選擇排序
1 for i := 1 to n-1 do 2 { 3 j := i ; 4 // 找出 a[i]到 a[n]中最小的一個整數 5 for k := i + 1 to n do 6 if (a[k] < a[j]) then j := k;//這是演算法的瓶頸所在 7 swap(a[i], a[j]);// swap(x, y) 將 x與 y的值互換 8 }
112/04/19 演算法 _ 第二章 2-30
選擇排序 第 4 行至第 6 行的迴圈會找出陣列 a[i :
n] 中最小元素的索引值 j 這固定需要 n-(i+1)+1 = n-I 次的比較運算
(第 6 行) 第 4 行至第 6 行的迴圈被第 1 行至第
8 行的外迴圈所包圍 i=0,n-1(n-i) = n-l + n-2 + … + 1 = (n-l)n/2 =
O(n2) = B(n) = A(n) = W(n)
112/04/19 演算法 _ 第二章 2-31
插入排序 原始資料 5 7 4 6 3
第一次排列 5 7 4 6 3
第二次排列 5 7 4 6 3
第三次排列 5 4 7 6 3
4 5 7 6 3
第四次排列 4 5 6 7 3
第五次排列 4 5 6 3 7
4 5 3 6 7
4 3 5 6 7
3 4 5 6 7
112/04/19 演算法 _ 第二章 2-32
插入排序 1 for j := 2 to n do 2 { // 把 a [j]插入到已經排序好的 a [1:j-1]中 3 tmp := a[j]; i := j-1; 4 // 幫 tmp 找出適當的位置 5 while ((i1) and (tmp<a[i])) do 6 { 7 a[i+1] := a[i]; i := i-1; 8 } 9 a[i+1] := tmp; 10 }
112/04/19 演算法 _ 第二章 2-33
插入排序 第 5 行至第 8 行的內迴圈在最好的情
況下只需要做 1 次的比對運算就知道 a [j] 的插入位置
在最差的情況下需要做 j-1 次的比較運算後才能把 a [j] 插入到適當的位置
平均起來需要做 (j-1)/2 次的比較運算後才能把 a [j] 插入到適當的位置
112/04/19 演算法 _ 第二章 2-34
插入排序 B(n) = j=2,n(1) = O(n)
W(n) = j=2,n (j-1) = 1 + 2 + … + n-2 + n-1 =
(n-l)n/2 = O(n2)
A(n) = j=2,n (j-1)/2= (1 + 2 + … + n-2 + n-
1)/2 = (n-l)n/4 = O(n2)
112/04/19 演算法 _ 第二章 35
演算法之最佳化與問題之複雜度
112/04/19 演算法 _ 第二章 2-36
最佳化的演算法 憑什麼說某一個演算法是所有可能用來解相同問題的演算法中最好的一個?
“ 最佳的”指的不是“已知中最好的”;而是“所有可能中最好的”
問題的複雜度
112/04/19 演算法 _ 第二章 2-37
我們可以搜尋、排序得多快? 證明解一個問題所需要的最少運算量 要找出一個好的演算法,我們必須做兩件事:
找出解決該問題的下限, L(n) ,其中 n 代表輸入的大小
發展或找出一個高效率演算法 A ,並且分析它的最壞情況複雜度, W(n)
如果 W(n) = L(n) ,則我們說 A 是一個最佳化的演算法
否則,我們可能可以發展出更好的演算法,或者找出更好的問題下限,或者兩者都可以
112/04/19 演算法 _ 第二章 2-38
問題的複雜度下限 為了確定一個問題的複雜度下限為 (g
(n)) ,我們必須證明:「解決該問題的每一個可能演算法它們的複雜度都是 (g(n)) 。」
112/04/19 演算法 _ 第二章 2-39
決策樹與一些問題的下限分析 5 個元素序列的循序搜尋之決策樹
x :a [1]
x :a [2]
x :a [3]
x :a [4]
x :a [5]
=
=
=
=
=
x=a [1]
x=a [2]
x=a [3]
x=a [4]
x=a [5] ]:1[ nax
112/04/19 演算法 _ 第二章 2-40
決策樹與一些問題的下限分析 8 個元素序列的二元搜尋之決策樹
x :a [4]
x :a [2]
x :a [1] x :a [3] x :a [5]
x :a [6]
x :a [7]
x :a [8]x<a
[1]
a[1
]<x<
a[2
]
a[2
]<x<
a[3
]
a[3
]<x<
a[4
]
a[4
]<x<
a[5
]
a[5
]<x<
a[6
]
a[6
]<x<
a[7
]a
[7]<
x<a
[8]
x>a
[8]
<
<<
<
<<
<
<
>
>
>
>
>>>
>
112/04/19 演算法 _ 第二章 2-41
決策樹與一些問題的下限分析
如果一棵樹有 n 個頂點,那麼這棵樹的高度必然大於等於 log2 n
其中當樹本身是平衡樹時其高度等於 log2 n
112/04/19 演算法 _ 第二章 2-42
決策樹與一些問題的下限分析
定理:(搜尋問題的下限與二元搜尋的最佳化性質)
i 任何一個利用比較的方式來解 n-元素序列的搜尋問題之演算法,
在最壞的情況下,至少需要 L(n) = log2 n + 1次的比較。
ii 二元搜尋演算法是最佳化的搜尋演算法。
112/04/19 演算法 _ 第二章 2-43
決策樹與一些問題的下限分析 3 個元素序列的排序之決策樹
a [1] :a [2]
a[1
]<a
[2]<
a[3
]
<
<
<
<
<
>
>
>
>
>a [2] :a [3] a [1] :a [3]
a [1] :a [3] a [2] :a [3]
a[1
]<a
[3]<
a[2
]
a[3
]<a
[1]<
a[2
]
a[2
]<a
[1]<
a[3
]
a[2
]<a
[3]<
a[1
]
a[3
]<a
[2]<
a[1
]
112/04/19 演算法 _ 第二章 2-44
決策樹與一些問題的下限分析 樹葉代表著最後的可能結果,即 n 個元
素的各種排列情況 總共有 n! 種排列情況 因此如果決策樹的樹葉數目是 p 的話,
那麼 p n!
最壞的情況指的是樹的高度
112/04/19 演算法 _ 第二章 2-45
決策樹與一些問題的下限分析 但是,我們知道如果樹的高度是 d ,那
麼 p 2d ,即 log2 p d
或者由於 p 是整數,我們可以寫成 d = log2p
我們得到d = log2 p log2 n!
112/04/19 演算法 _ 第二章 2-46
決策樹與一些問題的下限分析
定理:(排序問題的下限)
任何一個利用比較運算來解 n-元素序列的排序問題之演算法,
在最壞的情況下,至少需要 L(n) = log2 n! 次的比較。
112/04/19 演算法 _ 第二章 2-47
決策樹與一些問題的下限分析 史特林( Stirling )的近似公式:
因此
n
e
nnn
2!
nne
nnnn logloglog
2
12log!log
112/04/19 演算法 _ 第二章 2-48
決策樹與一些問題的下限分析 換句話說,任何一個排序演算法,只要
它的基本運算是兩個值的比較,那麼它的計算複雜度在最壞的情況下至少需要大約 n log n 次的比較
換句話說,排序問題的計算複雜度在最壞的情況下至少需要 (n log n) 次的比較
112/04/19 演算法 _ 第二章 2-49
決策樹與一些問題的下限分析 但是,合併排序演算法的最壞情況複雜
度便是 O(n log n)
因此我們說合併排序演算法是一個最佳化的排序演算法
(n log n) 已經是最佳化的下限了 排序問題的平均情況計算複雜度下限也
是 (n log n)
112/04/19 演算法 _ 第二章 2-50
決策樹與一些問題的下限分析 劣幣問題的計算複雜度下限 xiH 代表 xi 是劣幣而且它比真幣重、 xiL
代表 xi 是劣幣而且它比真幣輕 平衡樹高度是 log3 64 = 4
這意味著這個問題的下限是 4 ,至少需要使用 4 次天秤
112/04/19 演算法 _ 第二章 2-51
利用奇蹟來分析問題的複雜度下限 給定兩個已經排序過的序列 A[1:m] 與 B[1:n] ,
我們想知道的是將這兩個序列合併成一個排序過的序列,在最壞的情況下,至少需要多少次的比較運算
112/04/19 演算法 _ 第二章 2-52
利用奇蹟來分析問題的複雜度下限
112/04/19 演算法 _ 第二章 2-53
利用奇蹟來分析問題的複雜度下限 採用決策樹來分析
但是
n
nmlog
1),(MERGElog
nmnm
n
nm
112/04/19 演算法 _ 第二章 2-54
利用奇蹟來分析問題的複雜度下限
當 m 跟 n 的值一大一小時, 跟 m + n 1 之間的差距非常大
當 m 跟 n 的大小差不多時,傳統演算法所需要的比較次數其實已經是最佳化的下限了
n
nmlog
112/04/19 演算法 _ 第二章 2-55
利用奇蹟來分析問題的複雜度下限 假設我們所給的兩個輸入序列都有 m 個
元素,而且它們的合併結果將是 A[1] < B[1] < A[2] < B[2] < ··· < A[m] < B[m]
我們證明任何兩個相鄰的元素, A[i]:B[i] 以及 B[i]:A[i+1] ,都必須比較過,因此最少需要 2m-1 次的比較
112/04/19 演算法 _ 第二章 2-56
利用奇蹟來分析問題的複雜度下限 如果沒有比較 A[i] 與 B[i] ,那麼我們將無法區
分 A[1] < B[1] < ··· < A[i] < B[i] < ··· < A[m] < B[n] 與 A[1] < B[1] < ··· < B[i] < A[i] < ···< A[m] < B[n]這兩種情況
類似地,如果沒有比較 B[i] 與 A[i+1] ,那麼我們將無法區分 A[1] < B[1] < ··· < B[i] < A[i+1] < ··· < A[m] < B[n] 與 A[1] < B[1] < ··· < A[i+1] < B[i] < ··· < A[m] < B[n] 這兩種情況
因此,任何兩個相鄰的元素都必須比較過。我們總共有 2m 個元素,因此需要 2m-1 次的比較
112/04/19 演算法 _ 第二章 2-57
利用奇蹟來分析問題的複雜度下限 換句話說,當 m 跟 n 的大小差不多時,傳統演算法其實已經是最佳化的演算法
m+n1 次的比較其實也已經是最佳化的問題複雜度下限
A[1] < B[1] < A[2] < B[2] < ··· < A[m] < B[m] 便是所謂的奇蹟
112/04/19 演算法 _ 第二章 2-58
利用轉換來找出問題的下限 定義:令 P1與 P2為任意的兩個問題。如果 P1的任何一組輸
入資料都可以轉換成 P2的一組輸入資料,並且我們因此可以
在 (n) 的時間內利用 P2的解來求得 P1的解,則我們說問題
P1在 (n) 的時間內轉換成(reduced to)問題 P2,符號表示
成 P1 P2。
112/04/19 演算法 _ 第二章 2-59
利用轉換來找出問題的下限 P1 P2 意味著 P1 是比較簡單的問題而 P2 則
是比較難的問題 如果 P1 P2 所花的時間是 (n) ,而且解 P1
問題的複雜度下限是 T(n) ,則解 P2 所需要花的時間下限將是 T(n)(n)
如果轉換所需要的時間 (n) 小於 P1 問題的複雜度下限 T(n) ,則解 P2 所需要花的時間下限就是 T(n)(n) = T(n)
112/04/19 演算法 _ 第二章 2-60
利用轉換來找出問題的下限 假設 P1 所代表的問題
是排序問題,而 P2 則代表求凸面體的問題
假設排序問題的輸入是 n 個數目, x1, x2, …, xn
轉換程序是將每一個輸入數字 xi 轉換成平面上的一個點 (xi, xi
2)
1 2 3 4
1
4
9
16
112/04/19 演算法 _ 第二章 2-61
利用轉換來找出問題的下限 一旦 P2 求出這 n 個點的凸面體,那麼我們只
需要先找出 x 座標最小的點,然後以逆時針的方向將這個凸面體走一圈,經過每一個點時順便輸出該點的 x 座標值,即是我們要的排序過的資料
由於排序問題的下限是 (n log n) ,因此求凸面體問題的下限是 (n log n) O(n) = (n log n)