크래프톤 정글

[알고리즘] 재귀함수와 반복문에 대해서

yeoney 2024. 7. 9. 09:22
반응형

Q1. 재귀함수를 쓰는 이유

- 01. 재귀와 반복문을 비교해보기

[재귀 함수]

자기 자신을 호출하는 함수 ex) 피노나치 수열, 하노이의 탑 알고리즘, 팩토리얼 등등 .. 

  • 기본 : 함수 자체를 호출 한다
  • 체재 : 기본적으로 종료 조건만 지정 한다 (조건이 추가 될 수도 있음)
  • 종료 : 조건부 문은 함수 호출 본문에 포함되어 재귀 호출을 실행하지 않고 함수를 강제로 반환한다
  • 조건 : 기본적으로 조건에 수렴하지 않으면 무한 재귀가 발생한다
  • 무한반복 : 무한 재귀는 스택 오버플로우를 일으킴
  • 스택 메모리 : 스택 메모리는 함수가 호출 될 때마다 새 로컬 변수와 매개 변수 집합을 저장하는데 사용
  • 속도 : 느린 실행
  • 가독성 : 코드 길이와 변수가 적어 가독성이 높아짐

(특징)

1. 코드의 가독성이 좋다

2. 스택 메모리를 사용한다. 

 

[반복문]

for 문 

  • 기본 : 일련의 명령을 반복적으로 실행할 수 있다
  • 체재 : 반복에는 초기화, 조건, 루프 내의 명령문 실행 및 제어 변수 업데이트가 포함
  • 종료 : 특정 조건에 도달 할 때까지 반복적으로 실행
  • 조건 : 반복문의 제어 조건이 참이라면 무한 반복이 발생
  • 무한반복 : 무한 루프는 CPU 사이클을 반복적으로 사용
  • 스택 메모리 : 스택 메모리를 사용하지 않음
  • 속도 : 빠른 실행
  • 가독성 : 코드 길이를 더 길게 만들고 변수가 많아 가독성이 떨어짐

 

  재귀함수 반복문
정의 함수를 다시 호출하여 반복작업 실행 명령을 반복적으로 실행
스택 메모리 함수 호출 시 함수의 매개변수, 지역변수, 리턴값, 함수 종료 후 돌아가는 위치가 스택메모리에 저장 스택 메모리를 사용하지 않음
무한 반복 시 무한 재귀는 스택 오버플로우 발생 무한 루프는 CPU 사이클을 반복적으로 사용
속도 느린 실행 빠른 실행

- 02. 재귀와 반복문의 차이 

1. 메모리 

재귀함수는 함수를 반복적으로 호출하기 때문에 스택 메모리를 사용한다. ( 스택 오버플로우 발생 )

※ 스택오버플로우(stack overflow)란?
재귀함수 사용 시, 함수를 반복적으로 호출하므로, 스택메모리에 콜 스택이 쌓이게 된다. 이때 함수를 호출하는 횟수가 많아진다면 스택메모리를 초과하여 stack overflow가 발생하는 것이다. (일반적인 반복문 사용 시, 지역 변수들이 호출될 때 한번만 할당되기 때문에 이러한 일이 발생하지 않는다.)

반복문은 메모리 힙을 사용

2. 코드 길이 

재귀함수를 사용하면 반복문에 비해 코드 길이를 줄일 수 있다. 


- 03. 재귀 함수를 사용하는 두가지 이유

  • 알고리즘 자체가 재귀적인 표현이 자연스러운 경우 ( + 가독성 )  
    • f(n) = f(n - 1) + f(n - 2)
  • 변수 사용 을 줄일 수 있다.
    변수 사용을 줄여준다는 것은 변수가 잡는 메모리에 대한 이야기가 아니라, mutable state(변경 가능한 상태) 를 제거하여 프로그램 오류가 발생할 수 있는 가능성을 줄인다는 이야기이다. mutable state 를 최대한 피하는 것은 변수의 수를 줄이는 것과 변수가 가질 수 잇는 값의 종류 또는 범위를 정확히 제한하는 것이라고 생각하면 된다.  점화식을 보면, 결국 f(n)을 구하기 위해선 f(n - 1), f(n - 2)라는 자기자신의 함수를 인자만 바꾸고 다시 호출해야 한다. 이런 경우엔 반복문도 가능하지만, 재귀함수를 이용해서 간단히 구할 수 있다. 대부분 많은 사람들이 이 이유 때문에 재귀함수를 자주 사용 한다.

 

반복문의 예

let sum = 0;
for(let i = 0; i <= 100; i++) {
  sum += i;
}

 

재귀 함수

function sum(x) {
  if(x === 100) return x;
  else return x + sum(x + 1);
}

sum(0)

=> 변수 사용이 줄어든다 

 

 

반복문

function fibonacci(n) {
  let pre = 0;
  let cur = 1;
  let last = 0;
  for(let i = 1; i < n; i++){
    last = pre + cur;
    pre = cur;
    cur = last;
  }
  return last;
}

 

재귀 함수

function fibonacci(num) {
  if(num < 2) return num;
  return fibonacci(num - 1) + fibonacci(num - 2);
}

Q2. 왜 퀵소트를 가장 많이 쓰는 걸까? (

반응형