# 台北康橋G8A 11/6 遞迴 Recursion ## 函式複習 * 1. void (無回傳值) ``` void print(int a[], int n) { for(int i=0;i<n;++i) cout << a[i] << endl; } int main() { int a[] = {1, 2, 3, 4, 5}; print(a, 5); } ``` 2. int (回傳值為整數) ``` void print(int a) { cout << a << endl; } int square(int a) { return a*a; } int main() { int b = 10; // b = square(b); print(square(b)); } ``` ## 費氏數列 (Fibonaccii Sequence) $f_{n} = f_{n-1}+f_{n-2}, f_{0}=1, f_{1}=1$ $f(n)=f(n-1)+f(n-2)$ Initial states are important ``` int fibonaccii(int n) { if(n == 0 || n == 1) return 1; return fibonaccii(n-1) + fibonacci(n-2); } int main() { int n; cin >> n; cout << fibonaccii(n) << endl; } ``` ## 遞迴樹 (Recursion Tree) ## 階乘 (Factorial) $5!=5\times4\times3\times2\times1=120$ Initial state: $0!=1$ Recursion: $f(n)=?\times f(n-1)$ $n\times (n-1)\times (n-2)\times ...\times 1=?\times(n-1)\times(n-2)\times...\times 1$ ``` int factorial(int n) { ....... } int main() { int x; cin >> x; cout << factorial(x) << endl; } ``` ## 排列 (Permutation) 窮舉所有排列組合,如果有n個人排隊,總共就有$n!$種排法。 (用迴圈寫非常複雜) ``` int main() { int chosen[4] = {0}; int queue[4] = {0}; for(int i=1;i<=3;++i) { chosen[i] = 1; queue[1] = i; for(int j=1;j<=3;++j) { if(chosen[j] == 1) continue; chosen[j] = 1; queue[2] = j; for(int k=1;k<=3;++k) { if(chosen[k] == 1) continue; chosen[k] = 1; queue[3] = k; for(int a=1;a<=3;++a) { cout << queue[a] << " "; } cout << endl; chosen[k] = 0; } chosen[j] = 0; } chosen[i] = 0; } } ``` 用recursion實做permutation ``` // chosen[i] == 1 -> i 被選過了 // chosen[i] == 0 -> i 沒被選過了 int chosen[] = {}; int queue[] = {}; int permutation(int n, int x) { // n個人排隊,已經排好x個 if(n == x) { for(int i=1;i<=n;++i) cout << queue[i] << " "; cout << endl; return; } else { for(int i=1;i<=n;++i) { if(chosen[i] != 1) { queue[x+1] = i; chosen[i] = 1; permutation(n, x+1); chosen[i] = 0; } } } } int main() { permutation(5, 0); } ``` ## Recursion vs Loop Loop的優點:比較快 Recursion的優點: 很簡潔 遞迴計算第40項:0.83秒 迴圈計算第一千萬項:0.04秒 ``` int main() { int n; cin >> n; int f[100] = {1, 1}; for(int i=2;i<=n;++i) f[i] = f[i-1] + f[i-2]; cout << f[n] << endl; } ``` ## Memorization 把計算過的項先存在陣列裡面,可以避免recursion tree長得太龐大(空間換取時間) 速度是逼近loop ``` int arr[1000000] = {1, 1}; int f(int n) { if(arr[n] != 0) return arr[n]; arr[n] = f(n-1) + f(n-2); return arr[n]; } ``` ## Homework http://www.tcgs.tc.edu.tw:1218/ShowProblem?problemid=b022