일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
Tags
- PCA
- Machine Learning
- LG
- regression
- ChatGPT
- 머신러닝
- gpt
- LG Aimers
- supervised learning
- 지도학습
- 해커톤
- deep learning
- GPT-4
- 오블완
- OpenAI
- LLM
- 티스토리챌린지
- Classification
- AI
- 딥러닝
- LG Aimers 4th
- 분류
- 회귀
Archives
- Today
- Total
SYDev
[Data Structure] Chapter 02: 재귀(Recursion) 본문
Data Structure & Algorithm/Data Structure
[Data Structure] Chapter 02: 재귀(Recursion)
시데브 2023. 8. 7. 16:53재귀함수를 이해하고, 이를 활용하여 팩토리얼·피보나치 수열 등 여러 함수를 구현해보자.
재귀함수의 기본적인 이해
- 재귀함수: 함수 내에서 자기 자신을 다시 호출하는 함수를 의미한다.
재귀함수의 작동 원리는 위 그림의 형태와 같이 별도로 설정하지 않으면 멈추지 않고 계속 실행된다. 따라서, 특정 조건을 충족했을 때 재귀함수 호출이 멈추도록해야 하는데, 여기서 이 조건을 '재귀의 탈출조건'이라 한다.
이와 관련된 예제를 살펴보자.
#include <stdio.h>
void Recursive(int num)
{
if(num <= 0) //재귀의 탈출조건
return; //재귀의 탈출
printf("Recursive call! %d \n", num);
Recursive(num-1);
}
int main(void)
{
Recursive(3);
return 0;
}
Recursive call! 3
Recursive call! 2
Recursive call! 1
-> Recursive 함수에 0이 전달되면 '재귀의 탈출조건' 성립
팩토리얼: factorial
- 팩토리얼의 수식적 의미는 다음과 같다. $n! = n * (n-1) * (n-2) * . . . . * 2 * 1$
- 이를 다시 표현하면 다음과 같아진다. $n! = n * (n-1)!$
- n=0일 때, 팩토리얼의 값은 1이다.
#include <stdio.h>
int Factorial(int n)
{
if(n == 0) //n이 0일 때
return 1;
else //n이 1 이상일 때
return n * Factorial(n-1);
}
int main(void)
{
printf("1! = %d \n", Factorial(1));
printf("2! = %d \n", Factorial(2));
printf("3! = %d \n", Factorial(3));
printf("4! = %d \n", Factorial(4));
printf("9! = %d \n", Factorial(9));
return 0;
}
1! = 1
2! = 2
3! = 6
4! = 24
9! = 362880
피보나치 수열: Fibonacci Sequence
- $수열의 n번째 값 = 수열의 n-1번째 값 + 수열의 n-2번째 값$
- n=1일 때, 피보나치 수열의 값은 0이다.
- n=2일 때, 피보나치 수열의 값은 1이다.
#include <stdio.h>
int Fibo(int n)
{
if(n == 1)
return 0;
else if(n == 2)
return 1;
else
return Fibo(n-1) + Fibo(n-2);
}
int main(void)
{
int i;
for(i=1; i<15; i++)
printf("%d ", Fibo(i));
return 0;
}
0 1 1 2 3 5 8 13 21 34 55 89 144 233
코드의 실행흐름을 나타내자면 다음과 같아진다.
#include <stdio.h>
int Fibo(int n)
{
printf("func call param %d \n", n);
if(n == 1)
return 0;
else if(n == 2)
return 1;
else
return Fibo(n-1) + Fibo(n-2);
}
int main(void)
{
Fibo(7);
return 0;
return 0;
}
func call param 7
func call param 6
func call param 5
func call param 4
func call param 3
func call param 2
func call param 1
func call param 2
func call param 3
func call param 2
func call param 1
func call param 4
func call param 3
func call param 2
func call param 1
func call param 2
func call param 5
func call param 4
func call param 3
func call param 2
func call param 1
func call param 2
func call param 3
func call param 2
func call param 1
이진 탐색 알고리즘의 재귀적 구현
- Chapter 01에서 구현한 이진 탐색 알고리즘은 탐색 대상을 찾을 때까지 동일한 패턴을 반복한다.
#include <stdio.h>
int BSearchRecur(int ar[], int first, int last, int target)
{
int mid;
if(first>last)
return -1;
mid = (first+last) /2;
if(ar[mid] == target)
return mid;
else if(target < ar[mid])
return BSearchRecur(ar, first, mid-1, target);
else
return BSearchRecur(ar, mid+1, last, target);
}
int main(void)
{
int arr[] = {1, 3, 5, 7, 9};
int idx;
idx = BSearchRecur(arr, 0, sizeof(arr)/sizeof(int)-1, 7);
if(idx == -1)
printf("탐색 실패 \n");
else
printf("타겟 저장 인덱스: %d \n", idx);
idx = BSearchRecur(arr, 0, sizeof(arr)/sizeof(int)-1, 4);
if(idx == -1)
printf("탐색 실패 \n");
else
printf("타겟 저장 인덱스: %d \n", idx);
return 0;
}
하노이 타워: The Tower of Hanoi
- 모든 원반을 같은 형태로 A에서 C로 옮겨야 한다.
- 원반은 한 번에 하나씩만 옮길 수 있고, 옮기는 과정에서 작은 원반의 위에 큰 원반이 올라오면 안 된다.
- 위에서부터 순서대로 원판1, 원판2, 원판3 ...
하노이 타워의 반복패턴
- 가장 아래에 있는 원반을 제외한 나머지 모든 원판을 B로 옮긴다.
- 가장 아래에 있는 원반을 C로 옮긴다.
- 나머지 원반을 모두 C로 옮긴다.
이를 일반화시킨 과정을 다음과 같다.
- 작은 원반 n-1개를 A에서 B로 이동
- 큰 원반 1개를 A에서 C로 이동
- 작은 원반 n-1개를 B에서 C로 이동
- 이동해야 할 원반의 개수가 1개인 경우 그냥 A에서 C로 옮긴다.
하노이 타워 문제의 해결
#include <stdio.h>
void HanoiTowerMove(int num, char from, char by, char to) //num개의 원반을 from에서 by를 이용해서 to로 이동
{
if(num==1)
{
printf("원반1을 %c에서 %c로 이동 \n", from, to); //반복 패턴의 4단계
}
else
{
HanoiTowerMove(num-1, from, to, by); //반복 패턴의 1단계
printf("원반%d을(를) %c에서 %c로 이동 \n", num, from, to); //반복 패턴의 2단계
HanoiTowerMove(num-1, by, from, to); //반복 패턴의 3단계
}
}
int main(void)
{
// 막대A의 원반 3개를 막대B를 경유하여 막대C로 옮기기
HanoiTowerMove(3, 'A', 'B', 'C');
return 0;
}
원반1을 A에서 C로 이동
원반2을(를) A에서 B로 이동
원반1을 C에서 B로 이동
원반3을(를) A에서 C로 이동
원반1을 B에서 A로 이동
원반2을(를) B에서 C로 이동
원반1을 A에서 C로 이동
-> 함수 호출 순서, 코드의 실행흐름을 파악하려 애쓰지 말고 직관적으로 이해하자.
참고자료
- 윤성우, <윤성우의 열혈 자료구조>, 오렌지미디어, 2022.04.11
- https://imhere0729.tistory.com/3
[자료구조]재귀함수
1. 호출관계 를 중요시할것. 피보나치 수열. 0 1 1 2 3 5 8 13 21 34 55 . . . n=1 -> 0, n=2 -> 1 :: 0번째와 1번째는 결정되어 있다. n = otherwise -> fib(n-1)+fib(n-2) :: n번째 수는 n-1번째수 + n-2번째 수 [1_ex] int Fibo(int
imhere0729.tistory.com
'Data Structure & Algorithm > Data Structure' 카테고리의 다른 글
[Data Structure] Chapter 05: 원형, 양방향 연결 리스트 (0) | 2023.08.12 |
---|---|
[Data Structure] Chapter 04: 연결 리스트의 이해와 구현 (0) | 2023.08.11 |
[Data Structure] Chapter 03: 추상 자료형과 배열 기반 리스트 (0) | 2023.08.09 |
C언어에서의 구조체와 typedef (0) | 2023.08.08 |
[Data Structure] Chapter 01: 자료구조와 알고리즘 (0) | 2023.08.06 |