Professional Documents
Culture Documents
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-
演算法的表示與優劣
演算法的表示
自然語言
流程圖
…
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],0i,jn-1
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
#define SWAP(x,y,t)
(t = x, x = y, y = t)
輸入大量各式資料測試之。
若此為提供他人的程式,還應考慮輸入正
確性 (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
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)
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) 的設立,否則易造形成無窮迴圈 。
…
}
程序呼叫時流程的轉換
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 n2
若第一個月只有一對小 1 2 3 4 5 6
兔,第 n 個月會有多少 1
對費氏兔子?
1
此即為第 n 項費氏數列
:Fn = Fn1 + Fn2 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頂端前n1個圓盤搬移至B暫存;
將A頂端所剩的1個圓盤搬移至C;
將B頂端的n1個圓盤搬移至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
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
時 間 複 雜 度 ( 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
f(n) 指的是演算法的執行時間(步驟),
我們希望能找到 g(n);只要在 n n0 後,
cg(n) 一定會大於或等於 f(n),那麼就可
以用 O(g(n)) 來表示 f(n)。
S. J. Shyu -51-
f(n) = 4n2+174, g(n) = n2, c = 5;
請注意在上圖中,當n 14 (=n0) 之後,
cg(n) 一定會大於或等於 f(n)
c 消弭了硬體、程式語言、作業系統、
(5n 4n +174),
2 2
寫作技巧…的差異
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 (續)
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,當 nn0 時,
c1g(n) f(n) c2g(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 個數字中找出最大。
O(n)
f(n) (n)
(1)
S. J. Shyu n -64-
n n
(1) :至少需要常數次(1、300、10000... 與 n 無關) 的運算;
(n2) :至少需要 n2 次(讀入、檢視這 2n2 個矩陣內容) 運算;
O(n2) :利用迴圏逐步把兩矩陣對應的內容相加。
(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
Shyu, S. J.
S. J. Shyu -68-
1-68