순환(Recursion의 개념과 기본 예제 1
재귀란?
- 자기 자신을 호출하는 함수.
void func(...) { ... func(...); ... }
- 예시1. - 종료 조건이 없기때문에 ø무한루프에 빠진다.
public class Code01 { public static void main(String[] args) { func(); // 종료 조건이 없기때문에 무한루프에 빠짐. } public static void func() { System.out.println("Hello..."); func(); } }
- 예시2. - 적절한 종료조건을 사용하여 무한루프에 빠지지 않음.
public class Code02 { public static void main(String[] args) { int n = 4; func(n); } public static void func(int k) { if( k <= 0 ) { // Base case : 적어도 하나의 recursion에 빠지지 않는 경우가 존재해야 한다. return; } else { System.out.println("Hello..."); func(k-1); // Recursive case : recursion을 반복하다보면 결국 base case로 수렴해야 한다. } } }
- 적어도 하나의 base case가 존재해야한다. - 조건 1
- recursion을 반복하다 보면 결국 base case로 수렴해야한다. - 조건 2
- 조건 1과 조건 2가 충족해야 Recursion은 무한루프에 빠지지 않는다.
- 예시3. - 1~n의 합을 구하는 함수
public class Code01 { public static void main(String[] args) { int result = func(4); System.out.println(result); } public static int func(int n) { if(n<=0) { return 0; } else { return n + func(n-1); } } }
-
base case가 실행된 함수로 리턴된다. 0, 1, 3, 6, 10의 순서로 결과가 반환된다.
- recursion의 해석
public static int func(int n) { // 이 함수의 mission은 0~n까지의 합을 구하는 것이다. if (n==0) { return 0; // n=0이라면 합은 0이다. } else { return n + func(n-1); // n이 0보다 크면 0에서 n까지의 합은 0에서 n-1까지의 합에 n을 더한 것이다. } }
- 이 함수의 mission은 0~n까지의 합을 구하는 것이다.
- n=0이라면 합은 0이다.
- n이 0보다 크면 0에서 n까지의 합은 0에서 n-1까지의 합에 n을 더한 것이다.
-
- 순환함수와 수학적 귀납법
- 정리 : func(int n)은 음이 아닌 정수 n에 대해서 0에서 n까지의 합을 올바르게 계산한다.
- 증명 :
- n=0인 경우 : n=0인 경우 0을 반환한다. 올바르다.
- 임의의 양의 정수 k에 대해서 n < k 인 경우 0에서 n까지의 합을 올바르게 계산하여 반환한다고 가정하자.
- n=k인 경우를 고려해보자. func은 먼저 func(k-1) 호출하는데 2번의 가정에 의해서 0에서 k-1까지의 합이 올바로 계산되어 반환된다. 메서드 func은 그 값에 n을 더해서 반환한다. 따라서 func은 0에서 k까지의 합을 올바로 계산하여 반환한다.
- Recursion이 일반적인 예
- Factorial : n!
- 0! = 1
- n! = n*(n-1)! n>0
public static int factorial(int n) { if (n==0) { return 1; } else { return n*factorial(n-1); } }
-
factorial(4) <- return 4 * factorial(3) <- 3 * factorial(2) <- 2 * factorial(1) <- 1 * factorial(0) <- 1
- 정리 : factorial(int n)은 음이 아닌 정수 n에 대해서 n!을 올바로 계산한다.
- 증명 :
- n=0인 경우 : n=0인 경우 1을 반환한다. 올바르다.
- 임의의 양의 정수 k에 대해서 n<k인 경우 n!을 올바르게 계산한다고 가정하자.
- n=k인 경우를 고려해보자. factorial은 먼저 factorial(k-1) 호출하는데 2번의 가정에 의해서 (k-1)!이 올바로 계산되어 반환된다. 따라서 메서드 factorial은 k*(k-1)! = k! 을 반환한다.
- Fibonacci
public static int fibonacci(int n) { if (n < 2) { return n; } else { return fibonacci(n-1) + fibonacci(n-2); } }
- Euclid
- 유클리드 호제법은 최대 공약수를 구하는 방법이다.
- 두 수 a와 b가 있을 때 a를 b로 나눈 나머지는 r이라고 하자(단, a>b)
- a와 b의 최대공약수는 b와 r의 최대공약수와 같다고 하고, 이 성질에 따라 b를 r로 나눈 나머지를 구하고 다시 r을 r’로 나눈 나머지를 구하는 과정을 반복하여 나머지가 0이 되었을 때 나누는 수 b가 최대 공약수가 된다.
- 아래의 경우 p와 q 중 누가 큰지 작은지는 상관이 없는것이 만약 q가 p보다 크면 서로의 값이 바뀐다.
public static int gcd(int p, int q) { if(q==0) { return p; } else { return gcd(q, p&q); } }
- Factorial : n!
Comments