You are on page 1of 68

S. J.

Shyu -1-
資料結構、演算法
資料結構與演算法
簡單的資料結構
演算法初探
演算法的效率分析

S. J. Shyu -2-
資料結構、演算法
 「資料結構」(data structure):
在電腦中有效率地存放資料,使其
方便處理的學問;
 「演算法」(algorithm):
探討解決問題的策略。
 兩者相輔相成!
Algorithms + Data Structures = Programs
by Niklaus Wirth (Prentice-Hall)
(N. Wirth, 1934; Algol W, Pascal, Modula-2; Turing Award)
Niklaus Wirth on Teaching Computer Science
S. J. Shyu -3-
資料結構與演算法
 電腦處理的對象稱為「資料」(data),
泛指所有輸入至電腦中,即將、正在
或已經被電腦程式處理的符號總稱;
包括了數值(numerical) 資料、字串
(string) 資料等等,乃至於目前多媒
體 (multimedia) 軟體所處理的影像、
聲音、視訊等多媒體資料。

S. J. Shyu -4-
資料結構與演算法
 當這些資料集合在一起時,會因處理
需求的不同而存在一種或多種彼此之
間的特定關係,這些資料之間的邏輯
關係,就稱為結構 (structure)。
 研究資料的邏輯關係,
探討這些邏輯關係在電腦中的
表現 (representation) 和
處理 (manipulation) 方式,
即為「資料結構」。

S. J. Shyu -5-
 為解決實際生活中的許多問題,資
料之間的邏輯關係會因問題需求的
不同、或處理效率的考量而可能重
新組織,於是資料結構著重的是問
題需求和資料之間關係的各種課題。
 透過資料結構解決問題時,與演算
法之間確實有緊密結合的關係。我
們以資料結構的探討為主軸,輔以
因需求而產生的必要演算法。
 問題與演算法的關係將於演算法課
程中討論
S. J. Shyu -6-
 至於資料的邏輯關係以及與問題之間
求解之道,我們靠程式語言
(programming language) 做為中
間的橋樑,事實上問題要在電腦上解
決,少不了用程式語言將腦中解題的
演算方法,撰寫成軟體程式,予以實
作 (implement) 執行。
 書中討論的各種資料結構和演算法,
在所有類型的電腦上皆能透過適當的
程式語言,實作出來並正常運作。
S. J. Shyu -7-
簡單的資料結構
範例1-1 生活中常見的資料相互關係:
 校園中有一群人;
 每個中華民國國民皆有唯一的身分證字號;
 每位同學在班上皆有唯一的座號、在學校皆有
唯一的學號;
 在大學中的科系有系別、年級別、甚至於班別;
 排隊的時候,我們可能只關心排在前一位的是
誰?有時可能還在意排在自己前面的共有多少
人?
 外國旅行時,各景點間是否有班機直飛?
 上網尋找資料,網頁間的鏈結,將網頁連結成
複雜的全球性的網路 (world-wide web)。
S. J. Shyu -8-
演算法初探
 簡單地說「演算法」(algorithms) 就
是解決問題的方法過於抽象。
 在韋氏詞典 (Dictionary by Merriam-
Webster) 中,algorithm的解釋為:
『在有限步驟,解決數學問題的程序』
(a procedure for solving a mathematical
problem in a finite number of steps)。

S. J. Shyu -9-
Horowitz, Sahni和Mehta 給予演算法
明確的定義: 演算法是一組可完成特定工
作的指令集合,並且所有的演算法都需滿
足下列條件:
1. 輸入 (input):可以有多個其甚至是沒有輸入;
2. 輸出 (output):至少產生一個輸出;
3. 明確 (definiteness):每個指令都清楚明確;
4. 有限 (finiteness):在任何情況下,如果逐步追蹤
演算法的每個指令,演算法會在有限的步驟內結束;
5. 有效 (effectiveness):原則上每個指令都需基本到
只需紙和筆即可實踐之,並且每個指令的運算不止如
條件3 般明確而已,還必須是可正確求解的 (feasible)。
S. J. Shyu -10-
演算法的表示與優劣
 演算法的表示
 自然語言
 流程圖

 虛擬碼 (pseudo code)

 …

 Algorithms + Data structures


= Programs [Niklus Wirth]
(N. Wirth, 1934; Algol W, Pascal, Modula-2; Turing Award)
Niklaus Wirth on Teaching Computer Science

S. J. Shyu -11-
演算法的好壞程度

 實作演算法的效能評估
(performance evaluation)
 演算法複雜度分析
(complexity analysis)

S. J. Shyu -12-
程式撰寫流程
思考問題的解決方法是個抽象的思維過程
問題的需求或限制 ,電腦程式的輸出則是具象的結果呈現;
兩者之間的所有過程,都是成為程式設計師必須經歷的
磨練。資料結構與演算法的學習,正是必要的磨練之一
思考與探索 。

資料結構與演算法設計

試 程式撰寫


驗証、測試與修善

數學証明 結果輸出

S. J. Shyu
撰寫程式解決問題流程圖 -13-
範例 挑選排序法
 思考與探索:
 將整數由小至大排序, 可把數字小者放在左

邊,數字大者放在右邊, …
 可以挑出所有資料中最小者,做為左邊第一筆
資料,接著再挑出剩下資料中最小者,放在左
邊做為第二筆資料,依此類推,直至全部資料
都排列完成。
 若所有資料共計 n 筆,則會執行 n 次挑出最小

的運算,其第 i 次的運算,即為挑出未排序資
料中最小者,其結果做為第 i 筆資料。
自然語言表示演算法
S. J. Shyu -14-
演算法 挑選排序法:
輸入:data[0], data[1], data[2],..., data[n-1]
,共 n 筆整數資料
輸出:data[0], data[1],…, data[n-1];其中
若 i<j,則 data[i]data[j],0i,jn-1

for (i=0; i<n; i++)


虛擬碼表示演算法
{ data[j] = 挑出data[i]至data[n-1]中最小者
將 data[i] 和 data[j] 對調
// SWAP(data[i], data[j], temp)
}
如何做到?

S. J. Shyu -15-
0 1 2 3 … n-1
loop
control var.
0
list[0] list[min]
control var. j ==> i+1, i+2, … , n-1
min
i i+1 i+2 i+3 for
… (j=i+1; j<=n-1; j++) n-1
if (list[j] < list[min]) min = j
1 list[1] list[min]

2 list[2] list[min]

n-2

for (i=0; i<n-1; i++)


{ min = i;
for (j=i+1; j<=n-1;
list[min]=the j++)
minimum among list[i]~list[n-1]
if (list[j] < list[min]) min = j;
SWAP(list[i], list[min])
}Shyu, S. J. 1-16
程式 挑選排序法:
void SelectionSort(int data[], int n)
{ int i, j;
int min, temp; 以C語言實作演算法
for (i=0; i<n; i++) // i<n-1
{ min = i; input
for (j=i+1; j<n; j++) output
if (data[j]<data[min]) min = j;
definiteness
temp = data[i];
data[i] = data[min]; finiteness
data[min] = temp; effectiveness
}
SWAP(data[i], data[min], temp);
}
# define SWAP(x, y, t)(t=x, x=y, y=t)
S. J. Shyu -17-
SWAP(data[i], data[min], temp);

#define SWAP(x,y,t)
(t = x, x = y, y = t)

The macro works with any data type


temp = data[i];
data[i] = data[min];
data[min] = temp;
Shyu, S. J.
S. J. Shyu -18-
1-18
程式的驗証、測試與修繕
 數學証明―最佳的驗証;比較困難。
 測試―

 輸入大量各式資料測試之。
 若此為提供他人的程式,還應考慮輸入正

確性 (input validation)。
 若資料量非常大,則資料儲存用的陣列,

宜用動態配置的技巧宣告使用。
 ...

 修繕―列印過程檢驗為除錯不二法門。
S. J. Shyu -19-
程式1-2 挑選排序法
1 # include <stdio.h>
A possible 2
3
# include <time.h>
# define MAX_SIZE 10000
macro definition/declaration

program/ 4
5
# define SWAP(x, y, t) (t = x, x = y, y = t)
void genRndData(int [], int);
6 void selectionSort(int [], int);
implementation 7
8
void printData(int [], int);
int list[MAX_SIZE], n;
prototype declaration

for selection 9 clock_t t0, tx;


10 int main()
11 { printf("# data = ");
sort 12
13
scanf("%d", &n);
genRndData(list, n);
14 t0 = clock();
function call 15 selectionSort(list, n);
16 tx = clock();
17 printData(list, n);
18 printf("\ntime (sec.) = %f6.2",
(double) (tx-t0)/CLOCKS_PER_SEC);
19 return 1;
20 }
21 void genRndData(int list[], int n)
22 { int i;
23 srand(time(NULL));
24 for (i=0; i<n; i++) list[i] = rand() % MAX_SIZE;
25 printData(list, n);
26 }
function definition
27 void printData(int list[], int n)
28 { int i;
29 for (i=0; i<10; i++) printf("-");
30 for (i=0; i<n; i++) printf("\n[%d] = %d", i, list[i]);
31 printf("\n");
32 }
33 void selectionSort(int data[], int n)
34 { // 與程式1-1相同
Define variables/functions
35 } before call/reference macro call
S. J. Shyu -20-
Code Simplification and Readability
程式1-2 挑選排序法
int list[MAX_SIZE], n;
1 # include <stdio.h>
2 # include <time.h>
void sort(int list[], int n) 3 # define MAX_SIZE 10000
{ int i, j, min, temp; 4 # define SWAP(x, y, t) (t = x, x = y, y = t
for (i=0; i<n-1; i++) 5 void genRndData(int [], int);
{ min = i; 6 void selectionSort(int [], int);
for (j=i+1; j<n; j++) 7 void printData(int [], int);
if (list[j] < list[min]) min = j; 8 int list[MAX_SIZE], n;
SWAP(list[i], list[min], temp); 9 clock_t t0, tx;
} 10 int main()
}
11 { printf("# data = ");
12 scanf("%d", &n);
13 genRndData(list, n);
int main() 14 t0 = clock();
{ int i; 15 selectionSort(list, n);
printf("# data: "); 16 tx = clock();
scanf("%d", &n); 17 printData(list, n);
for (i=0; i<n; i++) 18 printf("\ntime (sec.) = %f6.2",
{ list[i] = rand()%1000; (double) (tx-t0)/CLOCKS_P
printf("\n[%d] = %d", i, list[i]); 19 return 1;
}
20 }
21 void genRndData(int list[], int n)
printf("\n"); 22 { int i;
sort(list, n); 23 srand(time(NULL));
for (i=0; i<10; i++) printf("-"); 24 for (i=0; i<n; i++) list[i] = rand() % M
for (i=0; i<n; i++) 25 printData(list, n);
printf("\n[%d] = %d", i, list[i]); 26 }
return 1; 27 void printData(int list[], int n)
} 28 { int i;
29 for (i=0; i<10; i++) printf("-");
30 for (i=0; i<n; i++) printf("\n[%d] = %d",
31 printf("\n");
32 }
33 void selectionSort(int data[], int-21-n)
Shyu, S. J.
S. J. Shyu
34 { // 與程式1-1相同 1-21
Implementation by CodeBlocks
C C++

S. J. Shyu -22-
S. J. Shyu -23-
Procedural Oriented Flow Control

S. J. Shyu -24-
Auto-Repetition

S. J. Shyu -25-
S. J. Shyu -26-
# include <time.h>
...
clock_t tx, t0;
...
t0 = clock();
SelectionSort(data, n);
tx = clock();
printf("time (sec.) = %.6f\n",
(float) (tx-t0)/CLOCKS_PER_SEC);
//cout<<"time (sec.) = “<<(float) (tx-t0)/CLOCKS_PER_SEC)<<endl;
//Memo1->Lines->Add("time (sec.) = “+FloatToStr((float) (tx-
t0)/CLOCKS_PER_SEC)));
S. J. Shyu -27-
GUI with More Object Oriented Design

Performance evaluation

https://sites.google.com/view/sjshyudsi
mf/programming-assignment/hw1-
selection-sort-vs-bubble-sort
S. J. Shyu -28-
S. J. Shyu -29-
 First Encounter
01-1_C++Builder_SelectionSort by S. J. Shyu
 https://www.youtube.com/watch?v=K2LnxsCM994
(1:03:53)

 Good Programming Style


01-2_C++Builder_BubbleSort_BinarySearch_SJShyu
 https://www.youtube.com/watch?v=uTJEZbY-WjM
(12:49)

 Better GUI
02-0_C++Builder_Better GUI by S. J. Shyu
 https://www.youtube.com/watch?v=R_3JJ3at5Pg&t=6s
(12:12)

S. J. Shyu -30-
遞迴演算法
 直接遞迴 (direct recursion):當程序執行完成前呼叫
了自己這個程序。
 間接遞迴 (indirect recursion) :在程序執行完成前
呼叫了其它會再度引用到自己的程序。
 在 設 計 遞 迴 程 式 時 , 切 記 終 結 條 件 ( termination
condition) 的設立,否則易造形成無窮迴圈 。

SS(data, n) void SS(int data[],int n)


{

}
程序呼叫時流程的轉換
S. J. Shyu -31-
範例 計算階乘
階乘的計算即可用遞迴的概念詮釋,請看:
n! = n(n-1)!
於是可以寫一個計算階乘的程序 X(int n),
它接受傳入的整數 n,傳回 n*X(n-1)
程式1-2
int X(int n)
{ if (n == 1) return 1;
return n*X(n-1);
}

S. J. Shyu -32-
範例
 一對費氏小兔出生後一  0 n  0;
個月可長為成兔 
 再一個月即可生育出一 Fn =  1 n  1;
對小兔,之後每月皆然 F  F n  2.
,且費氏兔子不會死去
 n 1 n2

 若第一個月只有一對小 1 2 3 4 5 6
兔,第 n 個月會有多少 1
對費氏兔子?
1
 此即為第 n 項費氏數列
:Fn = Fn1 + Fn2 11
(上個月的兔子對數) 111
+(上上個月的兔子會 11111
生出小兔的對數);
11111111
F0 = 0,F1 = 1。
1 1 2 3 5 8
S. J. Shyu -33-
範例1-5 河內塔 (Towers of Hanoi)
 柱A、B、C
 A: 起點、C:終點、B: 暫存
 n 個大小不一圓盤

 一次只能移動一個圓盤
 每次的移動只能取某柱頂
端的圓盤,移至另一柱的
頂端
 小圓盤不得在大圓盤之下

S. J. Shyu -34-
Hanoi ( disk, |, |, | );

Hanoi ( disk-1, |, |, | );
Hanoi ( 1, |, |, | );
Hanoi ( disk-1, |, |, | );

S. J. Shyu -35-
 將A頂端前n1個圓盤搬移至B暫存;
 將A頂端所剩的1個圓盤搬移至C;
 將B頂端的n1個圓盤搬移至C。
Hanoi ( n-1, A, C, B );
A B C A B C

Hanoi ( n, A, B, C );
Hanoi ( 1, A, B, C );
A B C

Hanoi ( n-1, B, A, C );
A B C

S. J. Shyu -36-
程式 搬運河內塔
1 void towerHanoi(int n, char A, char B, char C)
2 { if (n == 0) return;
3 towerHanoi(n-1, A, C, B);
4 cout<<“Move disk ”<<n<<“ from ”<<A<<“ to ”<<C;
5 towerHanoi(n-1, B, A, C);
6 }
1 void towerHanoi(int n, char A, char B, char C)
2 { if (n == 1)
3 cout<<“Move the top disk from ”<<A<<“ to ”<<C;
4 towerHanoi(n-1, A, C, B);
5 towerHanoi(1, A, B, C);
6 towerHanoi(n-1, B, A, C);
7 }
S. J. Shyu -37-
3個圓盤河內
塔遞迴程式
的流程轉換

S. J. Shyu -38-
河內塔問題的搬運次數
遞迴關係執行的次數即所需要的搬運次數
 令 T(n) 表示河內塔n個圓盤,而 T(1) = 1
 T(n) = T(n-1)+1+T(n-1)
= 2T(n-1)+1
= 2(2T(n-2)+1)+1 = 22T(n-2)+2+1
= 22(2T(n-3)+1)+2+1 = 23T(n-3)+22+2+1
= ... = 2n-1T(n-(n-1))+2n-2+...+22+2+1
= 2n-1+2n-2+ ... +22+2+1 = 1(2n-1)/(2-1)
= 2n-1
 亦即:搬運 n 個圓盤所需要的次數為 2n-1
 264−1=18,446,744,073,709,551,615264−1=18,446,744,073,709,551,615.
S. J. Shyu At a rate of one move per second, that is 584,942,417,355584,942,417,355 years! -39-
A B CD

範例 排列 A B DC
A C BD
A C DB
A DCB
 All permutations of A, B, C, D A DBC
B A CD
 A followed by all permutations of B, C, D
B A DC
 B followed by all permutations of A, C, D B C AD
B C DA
 C followed by all permutations of B, A, D
B DCA
 D followed by all permutations of B, C, A B DAC
CB A D
A, B, C, D CB DA

• A, B, C, D CA B D
CA DB
• B, A, C, D C DAB
• C, B, A, D C DBA
i • D, B, C, A DB CA
perm(0:n-1) ==> i+1 DB AC
DC BA
{0,1,…,n-1} || All permutations of perm(1:n-1) DC AB
DA CB
perm(n-1:n-1) ==> Boundary condition! DA BC
Shyu, S. J.
S. J. Shyu -40-
1-40
A B CD
程式1-5 產生排列 A B DC
A C BD
A C DB
void perm (char c[], int k, int n)
A DCB
{ // 產生 c[k],...,c[n-1] 的所有排列 A DBC
if (k == n-1) //終結條件成立時輸出此項排列 B A CD
B A DC
{ for (int i = 0; i < n; i++) B C AD
cout << c[i] <<" "; B C DA

cout << endl; B DCA


B DAC
} CB A D
else // 讓c[k]固定不動,求 perm(c[], k+1, n) CB DA
CA B D
{ for (int i=k; i<n; i++)
CA DB
{ SWAP(c[k], c[i], tmp); //讓c[k]~c[n-1]輪流當c[k]
C DAB
perm(c,k+1,n);//產生a[k+1],…,a[n-1]的所有排列C DBA
DB CA
SWAP(c[k], c[i], tmp); //還原原字元順序 DB AC
} DC BA
DC AB
}
DA CB
} DA BC
S. J. Shyu -41-
ABC 0 3
void perm (char c[], int k, int n)
{ int i;
if (k == n-1) //終結條件成立時輸出此項排列
{ for (i=0; i<n; i++) cout<<c[i]<<" ";
cout << endl;
}
else // 固定c[k],求 perm(c[], k+1, n)
k=0, i=2
{ for (i=k; i<n; i++)
k=0, i=1 CBA
{ k=0, tmp);
SWAP(list[k], list[i], i=0 CBA 1 3
perm(c,k+1,n); ABC BAC
ABC 1 3
SWAP(list[k], list[i], tmp); BAC 1 3 ABC
} BAC 1 3
} ABC ABC void perm (char c[], int k, int n)
} { int i;
ABC 1 3 if (k == n-1) //終結條件成立時輸出此項排列
void perm (char c[], int k, int n) { for (i=0; i<n; i++) cout<<c[i]<<" ";
{ int i; cout << endl;
if (k == n-1) //終結條件成立時輸出此項排列 }
{ for (i=0; i<n; i++) cout<<c[i]<<" "; else // 固定c[k],求 perm(c[], k+1, n)
cout << endl; { for (i=k; i<n; i++)
k=1,
{ SWAP(list[k], list[i], i=1 k=1, i=2
tmp);
}
else // 固定c[k],求 perm(c[], k+1, n) perm(c,k+1,n); BAC BCA
{ for (i=k; i<n; i++) BAC 2 tmp);
SWAP(list[k], list[i], 3 BCA 2
{ k=1,tmp);
SWAP(list[k], list[i], i=1 k=1, i=2 }
perm(c,k+1,n);
2 3 ABC
ABC tmp); ACB } BAC BAC
SWAP(list[k], list[i], ACB 2 }
3 void perm (char c[], int k, int n)
}
} ABC ABC { int i;
k=2, n=3, k==n-1
} if (k == n-1) //終結條件成立時輸出此項排列
{ for (i=0; i<n; i++) cout<<c[i]<<" ";
ABC 2 3 cout << endl;
}
void perm (char c[], int k, int n)
...
BAC BCA
{ int i;
k=2, n=3, k==n-1
if (k == n-1) //終結條件成立時輸出此項排列 }
{ for (i=0; i<n; i++) cout<<c[i]<<" "; ACB 2 3
cout << endl; 1. void perm (char c[], int k, int n)
} ABC 2. { int i;
k=2, n=3, k==n-1
else // 固定c[k],求 perm(c[], k+1, n) 3. if (k == n-1) //終結條件成立時輸出此項排列
{ for (i=k; i<n; i++) 4. { for (i=0; i<n; i++) cout<<c[i]<<" ";
cout << endl;
ACB
{ SWAP(list[k], list[i], tmp); 5.

perm(c,k+1,n); 6. }
S. J. Shyu SWAP(list[k], list[i], tmp); 7. else // 固定c[k],求 perm(c[], k+1, n) -42-
{ for (i=k; i<n; i++)
If NO 2nd SWAP
1. void perm (char c[], int k, int n)
2. { // 產生 c[k],...,c[n-1] 的所有排列
3. if (k == n-1) //終結條件成立時輸出此項排列
4. { for (int i = 0; i < n; i++)
5. cout << c[i] <<" ";
6. cout << endl;
7. }
8. else // 讓c[k]固定不動,求 perm(c[], k+1, n)
9. { for (int i=k; i<n; i++)
10. //讓c[k]~c[n-1]輪流當c[k]
11. { SWAP(c[k], c[i], tmp);
perm(c,k+1,n);
12. //產生a[k+1],…,a[n-1]的所有排列
13. SWAP(c[k], c[i], tmp);
}
14. }  ABC
15. }  ACB

 CAB
 CBA
 ABC
 ACB
Shyu, S. J.
S. J. Shyu -43-
1-43
S. J. Shyu -44-
 Powerful
 Express a process clearly
(complex otherwise)
 Easier to understand

 Any functions using


assignment, if-else and while
can be written recursively
S. J. Shyu -45-
演算法的效率分析
 什麼是有效率的演算法?
 效能評估 (performance evaluation)
 實作演算法取其執行時間、空間討論效率
 與電腦軟硬體設備有關 (machine dependent)
 效能分析 (performance analysis)
 分析演算法的執行時間和記憶體需求;以時間複雜
度或空間複雜度來討論演算法的效率
 客觀與電腦設備無關 (machine independent)
 以演算法或程式的指令執行次數 (program steps) 或程式
行數為焦點,執行指令個數愈少,效能大致愈好(暫不考
慮指令的種類)
S. J. Shyu -46-
複雜度

 時 間 複 雜 度 ( time complexity) :
一個程式或演算法所需的執行時間;
 空 間 複 雜 度 ( space complexity) :
一個程式或演算法所需的記憶體空間。
 解決相同的問題,演算法所用的時間
複雜度和空間複雜度愈少愈好。

S. J. Shyu -47-
演算法的執行次數
程式1-6 陣列元素加總 程式1-6將傳入整數陣
int Sum(int data[],int n) 列data 中的n個元素
{ int summation=0; (data[0]~data[n-1]),
for (int i=0; i<n; i++) summation += 總加至整數變數
data[i];
summation中傳出。
return summation;
} 程式1-7 陣列元素加總並計算所有指令執行的次數
int count = 0; // 全域變數宣告
count++; // 計算宣告 int 指令的執行
int Sum(int data[],int n)
{ int summation=0;
count++; // 計算宣告 int 指令的執行
在程式1-6中 for (int i=0; i<n; i++)
加入一全域
{ count++; // 計算 for 指令的執行次數
變數count, summation += data[i];
來加總所有 count++; // 計算 = 指令的執行次數;
指令執行的 }
次數;新的 count++; // 計算最後一次 for 指令的執行
程式將如程 count++; // 計算 return 指令的執行
式1-7所示。 return summation;
S. J. Shyu -48-
}
程式1-8 計算陣列元素加總所有指令執行的次數
count++;
int Sum(int data[],int n)
{ count++; // 計算宣告 int 指令的執行
for (int i=0; i<n; i++)
count += 2
count += 2;
}
 程式1-8 只保留程式1-7 的主體和加總count指令。
 此程式的執行總次數為 2n+4,其中 for 迴圈每執行一
次,count 會計數兩次;而迴圈共計有n次,所以 for
迴圈內即執行 2n 次。

S. J. Shyu -49-
1.5.2 演算法複雜度的表示方法: O、 和 
 假設有兩個演算法都可解決問題 P,其輸入資料量
為 n (見下圖)
 演算法 A 的估算執行次數為 4n2+174,
 演算法 B 的估算執行次數為 n3+5n+6

S. J. Shyu 在 n>7 後 演算法 A 比 B 好 -50-


用 表示上界、時間複雜度
定義:
f (n) = O(g(n)) 若且唯若存在兩個正數
c 和 n0,當 nn0 時,f (n)  cg (n)。

 f(n) 指的是演算法的執行時間(步驟),
我們希望能找到 g(n);只要在 n  n0 後,
cg(n) 一定會大於或等於 f(n),那麼就可
以用 O(g(n)) 來表示 f(n)。

S. J. Shyu -51-
f(n) = 4n2+174, g(n) = n2, c = 5;
請注意在上圖中,當n  14 (=n0) 之後,
cg(n) 一定會大於或等於 f(n)
c 消弭了硬體、程式語言、作業系統、
(5n  4n +174),
2 2
寫作技巧…的差異

所以O(n2) 足以代表 4n2+174 。


S. J. Shyu -52-
上界

f(n) = 4n2+174, g(n) = n2, c = 5;


cg(n)  n2
我們可稱 g(n) 為 f(n) 的上界 (upper bound)。

h(n) = n3, c = 5, ch(n)  n2


h(n) 亦為 f(n) 的上界 ;
但它是 trivial upper bound!
S. J. Shyu -53-
範例
a) 4n+12 = O(n),因為存在 c = 5,n0= 12,
使得 n  12 後,4n+12  5n(或 c = 6,
n0= 6,使得 n  6 後,4n+12  6n);
b) 10n+25 = O(n),因為存在 c = 11,n0= 25,
使得 n  25 後,10n+25  11n;
c) 8n2+11n+18 = O(n2),因為存在c = 9,n0 =
13,使得 n  13 後,8n2+11n+18  9n2;
d) 6×2n+n2 = O(2n),因為存在 c = 7,n0= 4,
使得 n4 後,6×2n+n2  7×2n;
S. J. Shyu -54-
範例 續

O ,因為存在 c ,n0 可任
取,使得 n  n0 後,  × ;
n2 n  O n ,因為找不到適當的 c
和n0,使得 n  n0 後, n2 n  cn;
n3 O n4 ,因為存在 c ,n0 ,
使得 n  後, n 3  n 4。

S. J. Shyu -55-
以 表示法分辨演算法的優劣
O(1) 稱為常數時間,即不論演算法的步驟須
需要多少指令,只要不像迴圈般重複執行,
皆視為常數時間;
O(n) 稱為線性時間,取其執行步驟的增加趨
勢與 n 的增加趨勢為線性關係之意;
O(n2) 為平方時間;依此類推,而
O(2n) 則稱為指數時間。
如此一來,我們會說 O(logn) 的演算法比
O(n) 來得有效率,O(n) 比 O(n2) 來得有效
率…。
S. J. Shyu -56-
1200

1000

O(1)
800
O(logn)
O(g(n))

O(n)
600
O(nlogn)
O(n2)
400
O(2n)

200

0
2 3 4 5 6 7 8 9 10
n

大O表示函數的優劣順序為:
O(1)  O(logn)  O(n)  O(nlogn)  O(n2)  O(n3)  O(2n)。
S. J. Shyu -57-
用 表示下界、問題的難易程度
  的定義如下: 假設 f g
f n  g n 若且唯若存在兩個正數
c 和 n0,當 n n0 時,f n c g n 。
 O 的符號方便討論「演算法的複雜
度」 (上界的概念) ;
  則可用來討論「問題的難易程度」
(下界的概念) 。

S. J. Shyu -58-
範例
a) 4n+12 = (n),因為存在 c = 1,n0= 1,使
得 n  1後,4n+12  n;
b) 10n+25 = (n),因為存在 c = 10,n0= 1,
使得n  1 後,10n+25  10n;
c) 8n2+11n+18 = (n2),因為存在 c = 1,n0 =
1,使得 n  1 後,8n2+11n+18  n2;
d) 6×2n+n2 = (2n),因為存在 c = 1,n0= 1,
使得n  1後,6×2n+n2  1×2n;

S. J. Shyu -59-
範例1-8 (續)

e) 326 = (1),因為存在 c = 1,n0可任取,


使得 n  n0 後,326  1×1;
f) 9n2+n+11  (n3),因為找不到適當的 c
和 n0,使得 n  n0 後,9n2+n+11  cn3;
g) 100n3 = (n2) = (n) = (1),因為存在c
= 1,n0= 1,使得n  1後,100n3  n2  n
 1。

S. J. Shyu -60-
最佳 演算法
 如果既可找到演算法 A 來解決問題 P,時間複雜度為
O(g(n)),且又能証明解決問題 P 的最少代價亦為
(g(n));
 亦即欲解決 P 的時間,至多要O(g(n)),至少為 (g(n));
不可能比多於O(g(n)),也不可能少於 (g(n))
(最多或最少都只是g(n)的常數倍),
 於是演算法 A 是解決問題 P 的最佳 (optimal) 演算法。
  的定義:
f(n) = (g(n)) 若且唯若
存在3個正數 c1、c2和 n0,當 nn0 時,
c1g(n)  f(n)  c2g(n)。
S. J. Shyu -61-
範例
n n,
因為存在c1 、c2 ,n0 ,
使得 n  後, n  n  n;

n2 n  n2 ,
因為存在 c1 、c2 ,n0 ,
使得 n 後, n2  n2 n 
n2。
S. J. Shyu -62-
Upper bound Lower bound
In practice 最多25學分/學期 NT99起
5天4夜 59999 大學學費至少 …
vague, fuzzy, obscure
In mathe-
matics
precise, concrete
In com- Algorithms for Hardness of the
plexity the problem problem
A cost already paid The least cost needed

S. J. Shyu -63-
n
 (1) :至少需要常數次(1、300、10000... 與 n 無關) 的運算;
 (n) :至少需要 n 次(讀入、檢視這 n 個數字) 的運算;
 O(n) :利用迴圏逐步在 n 個數字中找出最大。

 此演算法 (執行時間的上界) 與問題的下界,在 n 大時,有㇐


樣的成⾧趨勢 (只有常數係數的差異) 。
 上界無法降低、下界無法提高;該演算法為解此問題的最佳
演算法。

O(n)
f(n) (n)

(1)
S. J. Shyu n -64-
n n
 (1) :至少需要常數次(1、300、10000... 與 n 無關) 的運算;
 (n2) :至少需要 n2 次(讀入、檢視這 2n2 個矩陣內容) 運算;
 O(n2) :利用迴圏逐步把兩矩陣對應的內容相加。

 此演算法 (執行時間的上界) 與問題的下界,在 n 大時,有㇐


樣的成⾧趨勢 (只有常數係數的差異) 。
 上界無法降低、下界無法提高;該演算法為解此問題的最佳
演算法。
O(n2)
(n2)
f(n)

(1)
S. J. Shyu n -65-
O(n2) Insertion sort
n O(n2)
Heap sort
Selection sort
O(nlogn)
Heap sort ?
(nlogn)
為最佳排序演算法 利用二元樹的性質可
以得証
f(n) ?
(n)
至少需要 n 次(讀入、檢視
這 n 個數字) 的運算;

至少需要常數次
(1) (1, 300, 10000, ...
與 n 無關) 的運算

S. J. Shyu n -66-
O 

 對解決同㇐問題而言:
 演算法提供的解題時間上界愈低愈好

 証明問題所需運算的最少下界愈高愈好

 big-O 和  的概念,讓我們在程式寫作前即能運
籌帷幄—掌握演算法的效能及問題的難易
 最佳演算法的尋求,有了依循的方向
 電腦科學家不以寫程式解出問題為傲;但確以清
楚的邏輯思路、縝密的學理思維來設計好的演算
法解決問題為榮
S. J. Shyu -67-
Somethings we
should know

Dennis Ritchie,
Recipient of Turing Award
1983

Dennis Ritchie vs.


Steve Jobs

Shyu, S. J.
S. J. Shyu -68-
1-68

You might also like