게으른개발너D

[JS] 재귀 함수 1 본문

알고리즘/이론

[JS] 재귀 함수 1

lazyhysong 2023. 7. 18. 19:24

✨ 재귀함수

  • 재귀함수는 자기 자신을 호출하는 함수이다.
    • 자기 자신을 호출하는 것을 재귀 호출(Recursion call)이라고 한다.
  • 함수 호출은 Call stack에 쌓이기 때문에 스택 자료구조와 유사하게 동작한다.
  • 함수형 프로그래밍에선 루프 구현을 재귀로 구현하는 경우가 많다.
  • 잘못 작성하면 무한 루프에 빠질 수 있다.

 

Javascript에서 재귀함수

  • Call stack 제한이 있다.
    • 자바스크립트 엔진마다 제한 수는 다르다.
    • 크롬의 경우 약 1만개이다.
  • 재귀함수 성능 개선을 위한 꼬리 재귀(Tail recursion)가 제공되지 않는다.
  • 성능이 좋지 않다.

 

재귀로 구현해야 편한 알고리즘

  • Union-Find
  • DFS
  • Backtracking
  • 불편함을 무시한다면 더 빠른 성능으로 작성할 수 있지만 코딩 테스트는 빨리 푸는 것이 중요하기에 추천하지는 않는다.

 


✨ 재귀함수 예시 코드

1. 탈출 조건 작성하기

재귀 함수를 작성할 때는 반드시 탈출할 수 있는 조건을 작성해야 한다.

function recursion(a) {
  return recursion(a + 1);
}

이렇게 탈출 코드가 없으면 무한 루프에 빠진다.

자바스크립트에선 call 제한수가 있기때문에 결국 함수가 런타임 에러가 발생하게 된다.

 

따라서 if문 등의 조건문을 통해 탈출할 수 있는 코드를 작성해야한다.

function recursion(a) {
  if (a > 10) {
    return a;
  }
  return recursion(a + 1);
}

console.log(recursion(5)); // 11

 

2. 피보나치 수열

앞 두 항의 합이 뒤 항의 값이 되는 수열

// 1 1 2 3 5 8 13 ...
function fivonacci(x) {
  if (x <= 2) {
    return 1;
  }
  return fibonacci(x - 1) + fibonacci(x - 2);
}

console.log(fivonacci(7)); // 13

왼쪽 루트만 보자면 이런식으로 함수 호출이 진행된다.

3에서 내려온 fibonacci(2)와 fibonacci(1)은 탈출 루트를 통해 각각 1을 반환한다.

 

 

3. 변수 없는 합병 정렬 구현

분할 합병을 통한 정렬 구현

// 결합
const merge = (a, b) => {
  if (a.length === 0) {
    return b;
  } else if (b.length === 0) {
    return a;
  } else if (a[0] < b[0]) {
    return [a[0], ...merge(a.slice(1), b)];
  } else {
    return [b[0], ...merge(a, b.slice(1))];
  }
}

// 분해
const mergesort = (arr) => {
  if (arr.length < 2) {
    return arr;
  } else {
    const mid = Math.floor(arr.length / 2);
    const argu1 = mergesort(arr.slice(0, mid));
    const argu2 = mergesort(arr.slice(mid));
    return merge(argu1, argu2);
  }
}
const arr = [21, 10, 12, 20, 25, 13, 15, 22];
console.log(mergesort(arr));
// [10, 12, 13, 15, 20, 21, 22, 25]

 

Comments