본문 바로가기
JavaScript | 자바스크립트

재귀호출

by Pig_CoLa 2020. 7. 18.
SMALL

함수의 재귀호출이란

이름에서 유추할 수 있듯이 자기 자신을 호출하는 행위이다.

 

이때에 주의해야 할 점은 함수가 무한루프에 빠지지 않도록 작성 해줘야 한다.

사용법

사용방법 자체는 매우 간단하다.

함수 내에서 자기 자신을 호출하는 행위가 존재하면 된다.

위에서 언급한대로 무한루프에 빠지지 않도록 탈출구문을 작성해준다.

function logHi(num) {
    if (num === 0) {return}
    console.log('hi')
    logHi(num - 1)
}

logHi(3)
// hi
// hi
// hi
// undefined (return 값이 undefined일 뿐이다.)

입력받은 num의 수만큼 'hi'를 console.log를 통하여 출력하는 함수이다.

 

정말 별것 아닌 함수처럼 보이지만 이처럼 원하는 것을 정확하게 표현하기 위해선

탈출구문의 정확한 조건문 수립, 입출력 데이터의 타입, 상태등에 관한 고찰이 필요하다.

더 작은 단위에서 작업되도록 쪼개라

이는 구조체를 다룰때 매우 효과적인 방법이다.

숫자로만 이루어진 배열이 있다고 할 때

요소들을 모두 곱한 수를 출력하는 함수를 생각해보자.

function mulElement(arr) {
    let result = 1;
    for (let i of arr) {
        result *= i;
    }
    return result;
}

let numArr = [6,4,8,7,5,2,9]

mulElement(numArr) // 120960

재귀로 접근하지 않고 푼다면 위와같이 작성할 수 있다.

 

동일한 문제를 재귀로 접근했을 때 아래와 같이 작성할 수 있다.

function mulElement(arr) {
    if (arr.length === 0) {return 1}
    return arr[0] * mulElement(arr.slice(1));
}

let numArr = [6,4,8,7,5,2,9]

mulElement(numArr) // 120960

배열이 위 함수에서 재귀적으로 반복되었을때 최종적으로

arr은 어떤 배열이었든 빈배열인 상태가 된다.

(slice메서드를 통해 첫번째 요소만을 제외하여 재귀호출 하였기 때문)

 

빈배열인 상태를 탈출조건으로 설정하여 무한 루프에 빠지지 않도록 해주고

모든 요소의 곱 이라는 동작에 아무런 해가 가지 않는 1이란 값을 돌려주게 하였다.

 

이와같이 재귀함수를 올바르게 사용하기 위해선 입력받는 데이터의 형태나,

탈출조건을 정확히 수립하는것 뿐만 아니라 조건에 따른 return값을 무엇으로

해주어야 하는지도 상당히 중요하다.

재귀를 사용하는 이유 / 사용하기 적합한 상황

재귀함수로 문제해결이 가능하다는것은 while, for 등의 loop문으로도 충분히 표현이 가능하다.

다만 재귀를 사용할 수 있다면 코드가 훨신 간결해진다.

(이는 가독성에 충분히 유의미한 영향을 준다.)

 

재귀를 사용하기 가장 좋은 형태는 다음과 같다.

  1. while, for등의 중첩이 매우 많거나 그 정도를 알 수 없을때
  2. 구조가 동일(비슷)하거나 작은단위에서의 문제해결이 필요할때
for (let i = 0; i < n; i++) {
    for (let j = 0; j < n; j++) {
        for (let k = 0; k < n; k++) {
            for (let l = 0; l < n; l++) {
                for (let m = 0; m < n; m++) {
                    for (let n = 0; n < n; n++) {
                        for (let o = 0; o < n; o++) {
                            for (let p = 0; p < n; p++) {
                                                            // 무언가 수행할 코드
                                                        }
                        }
                    }
                }
            }
        }
    }
 }

재귀를 사용하지 않고 위와 같이 작성하게 된다면 작성하는 시간도 오래 걸릴 뿐만 아니라,

여러 동작과 여러 조건문이 들어가게 되는 경우 어디서 어떤 행동을 하는지 알기 힘들어진다.

이는 가독성을 매우 해치게되며, 오류발생시 해결하기 힘들게 만든다.

재귀적 사고력 증진

재귀함수를 잘 쓰기 위해선 재귀적으로 사고하는 능력을 길러야 한다.

필자가 생각하는 재귀적 사고의 흐름은 아래와 같다.

  1. 입값이 무엇인지, 출력값이 무엇인지 확실하게 생각한다.
    이는 재귀함수 뿐만아니라 모든곳에서 이런 과정이 필수적으로 동반되어야 한다.
  2. 나눌수 있는 제일 작은 단위로 나누어 생각한다.
    이때 제일 작은 단위가 들어왔을때와 그렇지 못할때의 흐름을 제어해라.
  3. 제일 작은 단위, 또는 전체적으로 공통된 작업이 필요한지를 분석하여 흐름에 맞게 배치해라.
    다차원 배열일경우 배열에서의 작업이 필요한것인지 더이상 배열이 아닌 요소에서 작업을 해야하는지 명확하게 구분하여 작성해야한다.
  4. 최종적으로 돌려주어야 할 값이 무엇인지 잊지말아라.
    재귀함수를 작성하다보면 여러 상황에 따른 return값들이 넘치게 된다.
    처음 함수를 호출했을때의 기대값이 무엇인지 잊어버리거나 로직내에서 놓치게 된다면, 원하는 값을 돌려줄 수 없다.

위와 같이 자신만의 사고의 흐름을 생각하며 여러 재귀함수를 만들어보아라.

재귀적 사고를 기르기 위해선 재귀를 쓸수 있는 상황에서 다양하게, 많이 해보는 수밖에 없다.

LIST

'JavaScript | 자바스크립트' 카테고리의 다른 글

OOP - 객체지향 / 상속  (0) 2020.07.29
복잡도 - 시간복잡도  (0) 2020.07.19
함수의 메서드 - call, apply, bind  (2) 2020.07.17
this  (0) 2020.07.16
DOM - 2  (0) 2020.07.16

댓글