Recursive function with examples
Q1. 최대공약수 (via Euclid Method)
m ≥ n인 두 양의 정수 m과 n에 대해서 m이 n의 배수이면 gcd(m,n)=n이고, 그렇지 않으면 gcd(m,n)=gcd(n,m%n)이다.
예를 들어, 두 수를 24, 30이라 할 때,
24 = 2 x 2 x 2 x 3, 30 = 2 x 3 x 5
최대 공약수(gcd) = 6 (공통된 약수는 2 * 3)
public static double gcd(int m, int n) {
if (m < n) {
// swap m and n
int temp = m;
m = n;
n = temp;
}
if (m%n == 0) {
// m이 n의 배수이면 gcd(m,n)=n
return n;
} else {
return gcd(n, m%n);
}
}
좀 더 간단한 버전은,
public static int gcd(int p, int q) {
if (q==0) {
return p;
} else {
return gcd(q, p%q);
}
}
Q2. 문자열의 길이 계산
간단하게 라이브러리를 사용해서 구할 수도 있지만, 재귀를 사용하여 문자열의 길이를 계산해보면 아래와 같이 생각할 수 있다.
public static int length(String str) {
if (str.equals("")) { // 빈 문자열인 경우
return 0;
} else {
return 1+length(str.substring(1));
}
}
Q3. 문자열을 한 글자씩 출력하기
이 역시 재귀를 사용해보자.
public static void printChars(String str) {
if (str.length()==0) { // 빈 문자열인 경우
return;
} else {
System.out.print(str.charAt(0)); // 맨 앞의 문자열을 출력
printChars(str.subString(1)); // 이후 문자열을 매개로 하여 재귀함수 호출
}
}
Q4. 문자열을 역순으로 출력하기
잘 생각해보면 Q3의 경우와 조금만 다르다!
public static void printCharsReverse(String str) {
if (str.length()==0) {
return;
} else {
printCharsReverse(str.substring(1));
System.out.print(str.charAt(0));
}
}
Q5. 2진수로 변환하여 출력
재귀함수를 사용하여 음이 아닌 정수 n을 이진수로 변환하여 출력한다.
public void printInBinary(int n) {
if (n < 2) { // 즉, 0 혹은 1이라면
System.out.print(n);
} else {
// n을 2로 나눈 몫을 먼저 2진수로 변환하여 출력한다
printInBinary(n/2);
// n을 2로 나눈 나머지를 출력한다
System.out.print(n%2);
}
}
Q6. 배열의 합 구하기
public static int sum(int n, int[] data) {
if (n <= 0) { // 더 이상 더할 정수가 없다면
return 0;
} else {
// 입력받은 data[0]에서 data[n-1]까지의 합을 구하여 출력한다
return sum(n-1, data) + data[n-1];
}
}
Q7. 데이터파일로부터 n개의 정수 읽어오기
Scanner 함수를 통해 참조하는 파일로부터 n개의 정수를 입력받아 배열 data에 저장한다.
public void readFrom(int n, int[] data, Scanner in) {
if (n == 0) {
return;
} else {
readFrom(n-1, data, in);
data[n-1] = in.nextInt();
}
}
Q8. 순차탐색
배열의 앞에서부터 target 변수값과 일치하는 값을 찾아 반환한다.
public int search(int[] data, int begin, int end, int target) {
if (begin > end) {
return -1;
} else if (target == items[begin]) {
return begin;
} else {
return search(data, begin+1, end, target);
}
}
배열을 반으로 나눠 찾는 경우엔 아래와 같다
public int search(int[] data, int begin, int end, int target) {
if (begin > end) {
return -1;
} else {
int middle = (begin+end)/2;
if (data[middle] == target) return middle;
int idx = search(data, begin, middle-1, target);
if (idx != -1) { // 앞에서 찾은 경우
return idx;
} else { // 뒤에서 찾은 경우
return search(data, middle+1, end, target);
}
}
}
Q9. 최대값 찾기
배열의 첫번째 값과 나머지 값을 비교하여 찾는 방법
public int findMax(int[] data, int begin, int end) {
if (begin == end) {
return data[begin];
} else {
return Math.max(data[begin], findMax(data, begin+1, end));
}
}
혹은, 배열을 반으로 나눠 찾는 방법도 있다.
public int findMax(int[] data, int begin, int end) {
if (begin == end) {
return data[begin];
} else {
int middle = (begin+end)/2;
int max1 = findMax(data, begin, middle);
int max2 = findMax(data, middle+1, end);
return Math.max(max1, max2);
}
}
Q10. Binary Search
기본적으로 배열에 데이터가 크기순 혹은 오름차순으로 정렬되어 있을 때 적용할 수 있는 방법이다.
public static int binarySearch(String[] items, String target, int begin, int end) {
if (begin > end) { // 빈 배열일 때
return -1;
} else {
int middle = (begin+end)/2;
int compResult = target.compareTo(items[middle]);
if (compResult == 0) {
return middle;
} else if (compResult < 0) {
return binarySearch(items, target, begin, middle-1)
} else {
return binarySearch(items, target, middle+1, end);
}
}
}
Tips
- Recursion vs Iteration
- 모든 순환함수(Recursion)은 반복문(Iteration)으로 변경 가능하다
- 그 역도 성립한다. 즉, 모든 반복문은 Recursion으로 표현 가능하다
- 순환함수로 복잡한 알고리즘을 단순하고 알기쉽게 표현할 수 있지만, 함수 호출에 따른 오버헤드가 있다 (매개변수 전달, 액티베이션 프레임 생성)