본문 바로가기
👩‍💻 Programming/Algorithms & Data Structures

재귀 알고리즘(Recursive Algorithms)

by codingBear 2022. 4. 7.
728x90
반응형

References

이번 글은 아래 자료들을 참고하여 작성하였습니다.
Recursive Algorithms on Khan Academy
Think Like a Programmer


위 인형은 러시아의 전통 인형 마트료시카이다. 큰 인형을 열면 그보다 작은 인형이 하나 나오고 다시 그 인형을 열면 또 작은 인형이 나오고를 반복하며 점점 크기가 작아진다. 재귀 함수도 이와 마찬가지로 주어진 조건을 충족할 때까지 함수 자신의 크기를 줄여가다 조건을 충족하면 결과값을 반환하는 함수이다.


배열 내 값 모두 더하기

// solution 1.
const numArr1 = [1, 2, 3, 4, 5];

function iterativeArraySum(array, size) {
  let sum = 0;

  for (let i = 0; i < size; ++i) {
    sum += array[i];
  }
  return sum;
}

console.log(iterativeArraySum(numArr1, numArr1.length)); // 15

위 코드는 주어진 배열의 길이만큼 for문으로 주어진 배열을 탐색하여 배열 내 모든 값의 합을 반환하는 함수이다. 이 함수를 살펴보면 배열 index 0부터 끝까지 탐색하며 값을 하나하나 더해나가는 것을 알 수 있다. 일정 조건 하에 반복 작업을 수행하는 함수라면, 반복문 대신 재귀 함수로 바꿔 쓸 수 있다.

위 함수를 완전한 재귀 함수로 바꿔 쓰기 전에 위 반복문은 그대로 놔둔 채 다른 기능을 수행하는 함수를 추가하여 보다 재귀 함수와 가까워지게 작성해보자.

// solution 2.
function iterativeArraySum(array, size) {
  let sum = 0;

  for (let i = 0; i < size; ++i) {
    sum += array[i];
  }
  return sum;
}

function arraySumDelegate(array, size) {
  if (size === 0) return 0;
  // the last number in the array is stored in this local variable
  const lastNum = array[size - 1];
  // the sum of all the other values in the array is computed and this result is stored in this local variable
  const allButLastSum = iterativeArraySum(array, size - 1);
  return lastNum + allButLastSum;
}

console.log(arraySumDelegate(numArr1, numArr1.length)); // 15
  1. 주어진 배열의 길이가 0이라면 결과값 0반환.
  2. 주어진 배열의 길이가 0보다 크다면 반복문을 호출하여 size의 값이 0이 될 때까지 배열값 더하기 작업 수행

위의 함수를 재귀 함수로 바꾸기 위해서는 iterativeArraySum으로 호출하는 반복문을 지금 실행 중인 함수로 치환하면 된다. 작성하면 아래와 같이 된다.

// solution 3.
const numArr1 = [1, 2, 3, 4, 5];

function arraySumRecursive(array, size) {
  if (size === 0) return 0;

  const lastNum = array[size - 1];
  const allButLastSum = arraySumRecursive(array, size - 1);

  return lastNum + allButLastSum;
}

console.log(arraySumDelegate(numArr1, numArr1.length)); // 15

위의 함수를 실행하게 되면 size의 값이 0이 될때까지 해당 작업을 반복하며 배열 내 값을 모두 더한다. solution 2.에서는 allButLastSum에 해당하는 값으로 다른 반복문을 불러왔다면, 여기서는 자기 자신을 호출함으로써 재귀적 작업을 수행한다.


Recursive Algorithms 활용 예들

The Factorial Function

const factorial = function (n) {
  // base case:
  if (n === 0) {
    return 1;
  }

  return n * factorial(n - 1);
};

console.log(factorial(5)); // 120

위의 함수는 1부터 n까지 자연수의 곱을 계산하는 함수이다. n-1을 설정하여 함수 factorial이 재귀적으로 쓰인 것을 볼 수 있다.


determine palindrome

const firstCharacter = function (str) {
  return str.slice(0, 1);
};

// Returns the last character of a string str
const lastCharacter = function (str) {
  return str.slice(-1);
};

// Returns the string that results from removing the first
//  and last characters from str
const middleCharacters = function (str) {
  return str.slice(1, -1);
};

const isPalindrome = function (str) {
  // base case #1
  if (str.length <= 1) return true;
  // base case #2
  if (firstCharacter(str) === lastCharacter(str))
    return isPalindrome(middleCharacters(str));
  // recursive case
  return false;
};

const checkPalindrome = function (str) {
  console.log("Is this word a palindrome? " + str);
  console.log(isPalindrome(str));
};

checkPalindrome(""); // true
checkPalindrome("a"); // true
checkPalindrome("motor"); // false
checkPalindrome("rotor"); // true

위의 코드는 주어진 문자열이 palindrome인지 판별하는 함수이다. 입력값이 없거나 하나인 경우 palindrome이기 때문에 true를 반환한다. 입력값의 길이가 2 이상인 경우 첫째값과 마지막 값을 잘라내어 일치 여부를 확인하고 나머지 중간값을 반환, 다시 반환된 중간값의 첫째값과 마지막값의 일치 여부를 확인하는 작업을 반복한다. 작업을 마친 후 palindrome이라면 true, 아니라면 false를 반환한다.


Fibonacci Series

function fib(n) {
  if (n < 2) {
    return n;
  }

  return fib(n - 1) + fib(n - 2);
}

console.log(fib(9)); // 34

위 함수는 피보나치 수열을 재귀 함수로 작성한 것이다. 함수를 실행하면 앞의 수와 앞앞의 수를 더하는 작업을 반복하여 입력값 n번째 위치하는 피보나치의 수를 구한다.



함께 보기

Fibonacci
Palindromes
Towers of Hanoi

728x90
반응형

댓글