第 5 章遞迴

15
1 第 5 第 第第

Upload: tyson

Post on 05-Jan-2016

49 views

Category:

Documents


5 download

DESCRIPTION

第 5 章遞迴. 目次. 5.1 遞迴的運作方式 5.2 一個典型的遞迴範例:河內塔 5.3 另一個範例:八個皇后 5.4 何時不要使用遞迴. 5.1 遞迴的運作方式. 何謂遞迴 (Recursive) ? 一個呼叫它本身的函數 撰寫遞迴時,一定要有「 結束點 」 Ex 1 : n 階層 ( 某一數 A 的階層 = A * (A-1) 階層 ) n! = n * (n-1)! (n-1)! = (n-1) * (n-2)! (n-2)! = (n-2) * (n-3)! : - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 第  5  章遞迴

1

第 5 章 遞迴

Page 2: 第  5  章遞迴

2

目次

5.1 遞迴的運作方式5.2 一個典型的遞迴範例:河內塔5.3 另一個範例:八個皇后5.4 何時不要使用遞迴

Page 3: 第  5  章遞迴

3

5.1 遞迴的運作方式

何謂遞迴 (Recursive) ?– 一個呼叫它本身的函數– 撰寫遞迴時,一定要有「結束點」

Ex 1 : n 階層 ( 某一數 A 的階層 = A * (A-1) 階層 ) n! = n * (n-1)!

(n-1)! = (n-1) * (n-2)! (n-2)! = (n-2) * (n-3)!

: :  1! = 1

Page 4: 第  5  章遞迴

4

5.1 遞迴的運作方式 (con.t)

以遞迴方式計算 n! ( 結束點為 n = 1)int fact(int n){ int ans; if(n == 1) ans = 1; else ans = n * fact(n-1) return ans;}

Page 5: 第  5  章遞迴

5

5.1 遞迴的運作方式 (con.t)

以圖形表示 n! 的做法 ( 以 4! 為例 )

num = fact(4);

n = 4;ans = 4 * fact(3);return(ans);

n = 3;ans = 3 * fact(2);return(ans);

n = 2;ans = 2 * fact(1);return(ans);

n = 1;ans = 1;return(ans);

6

2

1

24

Page 6: 第  5  章遞迴

6

5.1 遞迴的運作方式 (con.t)

Ex 2 :費氏數列 (Fibonacci number)– 某一數為其前二個數的和

假設 n0=1 , n1=1 ,則

n2 = n1+n0=1+1=2

n3 = n2+n1=2+1=3

::

∴ ni = ni-1+ni-2

Page 7: 第  5  章遞迴

7

5.1 遞迴的運作方式 (con.t)

費氏數列函數int fibon(int n){ int ans; if(n == 0 || n == 1) ans = 1; else

ans = fibon(n-1)+fibon(n-2); return(ans);}

Page 8: 第  5  章遞迴

8

5.2 一個典型的遞迴範例:河內塔

河內塔遊戲規則:– 每次只能搬一個盤子– 盤子有大小之分,而且大盤子在下,小盤子在上

河內塔搬移的演算法– 假使 n = 1 ,則– 搬移第一個盤子從 A 至 C

否則– 搬移 n–1 個盤子從 A 至 B– 搬移第 n 個盤子從 A 至 C– 搬移 n–1 個盤子從 B 至 C

Page 9: 第  5  章遞迴

9

5.2 一個典型的遞迴範例:河內塔 (con.t)

河內塔片段程式void tower(char from,char to,char aux,int n){ if ( n == 1 ) printf("Move disk 1 from %c to %c\n",from,to); else{ tower(from,aux,to,n-1); /* 將 from 標記中的 n-1 個金盤子,藉助

to 標記的柱子,搬到 aux 標記的柱子 */ printf("Move disk %d from %c to %c\n",n,from,to); tower(aux,to,from,n-1); /* 將 n-1 個盤子從 aux ,藉助 from 搬到 to */ }

}

Page 10: 第  5  章遞迴

10

5.3 另一個範例:八個皇后

八個皇后遊戲規則– 皇后之間不可在同一列 (row) 、同一行 (column) ,也不

可以在同一個對角線 (diagonal) 上。– 左上角為 ( 第一列、第一行 )

八個皇后牽涉到的觀念– 遞迴– 往回追蹤 (Backtracking)

Page 11: 第  5  章遞迴

11

5.3 另一個範例:八個皇后 (con.t)

/* 測試在 (row,col) 上的皇后是否遭受攻擊,遭受攻擊傳回值為 1 ,否則為 0 */int attack (int row, int col){

int i,atk = FALSE;int offset_row,offset_col;i = 0;while ( !atk && i < col ){

offset_col = ABS(i - col);offset_row = ABS(queen[i] - row);/* 判斷兩皇后是否在同一列 , 皇后是否在對角線上 *//* 若皇后同列或在對角線上則產生攻擊 ,atk == TRUE */atk = (queen[i] == row) || (offset_row == offset_col);i++;

}return atk;

}

Page 12: 第  5  章遞迴

12

5.4 何時不要使用遞迴

遞迴雖然可以使用少數幾行的敘述就可解決一複雜的問題,但有些問題會導致花更多的時間,因此在何時使用遞迴是很重要的。

遞迴樹 (recursive tree) Ex :費氏數列

– 遞迴– 非遞迴,即以反覆的 (interaive) 方式執行– 遞迴 vs. 非遞迴 ( 課本表 5.1)

Page 13: 第  5  章遞迴

13

5.4 何時不要使用遞迴 (con.t)

費氏數列 – 非遞迴int fibon(int n){ int ans, i; int backbone = 1, backtwo = 2; if (n == 0 || n == 1) ans = 1; else{ for(i = 2; i<=n;i++){ ans = backone + backtwo; backtwo = backone; backbone = ans; } } return ans;

}

Page 14: 第  5  章遞迴

14

5.4 何時不要使用遞迴 (con.t)

Ex : n! 的遞迴 遞迴 非遞迴int fact(int n) int fact(int n){ {

int ans; int i, ans = 1; if (a==1) for (i=n; i ; i--)≦ ans = 1; ans *= i; else return ans; ans = n*fact(n-1); } return ans;}

Page 15: 第  5  章遞迴

15

5.4 何時不要使用遞迴 (con.t)

建議使用遞迴的時機– 遞迴樹類似一棵木 ( 如費氏數列的圖 ) ,但重覆動作很少時– Ex :八個皇后

建議使用非遞迴的時機– 遞迴樹類似灌木,但重覆動作很多的– 遞迴樹類似一條通道的– Ex :費氏數列、 n!