본문 바로가기
the others/Algorithm

재귀함수 Recursion

by ciocio 2021. 8. 30.

Achivement Goals

 

✅  재귀의 의미에 대해서 이해하고, 자바스크립트에서 재귀 호출을 할 수 있다.

✅  재귀를 언제 사용해야 하는지 알고 있다.

✅  재귀적 사고 연습을 통해 재귀 함수를 base case와 recursive case로 나눠서 작성할 수 있다.

✅  자료 구조 중 Tree 구조에 재귀 함수를 사용하는 이유를 이해할 수 있다.

✅  실생활에 사용되는 유용한 Tree 구조를 알고 있다.

✅  깊이를 알 수 없는 Tree 구조에 재귀 함수를 활용하여 모두 순회(traverse)할 수 있다.

 

 

📌  재귀란?

 

어떤 문제를 해결할 때, 동일한 구조의 더 작은 문제를 해결함으로써 주어진 문제를 해결하는 방법이다.

 

-->  처음 접했을 때는 이게 무슨말이야 ...? 했는데 공부해보니까 알겠다.

-->  코드를 짜는 게 중요한 게 아니고 짜기 전에 생각하는 게 중요하다.!

-->  로직을 충분히 생각한다음에 짜야 문제가 풀림. 에라 모르겠다 코드 쓰자~! 하면 절.대. 안풀림

 

 

 

📌  재귀를 이용해 JSON.stringify( ) 메서드 구현하기  -->  시도했으나 실패 ~! ~!

 

 function stringifyJSON(obj) {
  // obj가 숫자일 때
  if(typeof obj === 'number'){return String(obj);}
  // obj가 boolean일 때
  if(typeof obj === 'boolean'){return String(obj);}
  // obj가 null일 때
  if(obj === null){return String(obj);}
  // obj가 문자열일 때
  if(typeof obj === 'string'){return `"${obj}"`;}
  // obj가 배열일 때
  if(Array.isArray(obj)){
    let result = [];
    for(let el of obj){
      result.push(JSON.stringify(el));
    }
    return `[${result}]` 
  }
  // obj가 객체일 때
  else{

    let finalStart = "{";
    let finalLast  = "}";
    let str = '';

    for(let key in obj){
      
      if(typeof obj[key] === 'function' || obj[key] === undefined){
        continue;
      }
  
      str += ('\"' + key +'\"');
      str += ':';
      if(typeof obj[key] === 'boolean' || obj[key] === null){
        str += obj[key];
      }
      else if(Array.isArray(obj[key]) || typeof obj[key] === 'object'){
        str += stringifyJSON(obj[key]);
      }
      else{
        str += ('\"' + obj[key] +'\"');
      }
      str += ',';
        
    }
    return finalStart + str.slice(0, -1) + finalLast;
  }

};

 

 

사실상 재귀는 거의 사용하지 않았다 ㅎㅎㅎㅎㅎㅎㅎ 💦💦

배열에서 JSON.stringify( )를 사용한 게 마음이 상해, 객체만은 재귀 함수를 쓰려고 엄청 노력했다. 

결과적으로 JSON.stringify( ) 메서드를 사용한 듯한 결과를 도출해냈다 !!

 

 

📌  재귀를 이용해 JSON.stringify( ) 메서드 구현하기  -->  리팩토링 해보자 ~~~!!

 

function stringifyJSON(obj) {
  // obj가 숫자일 때
  if(typeof obj === 'number'){return `${obj}`;}
  // obj가 boolean일 때
  if(typeof obj === 'boolean'){return `${obj}`;}
  // obj가 null일 때
  if(obj === null){return `${obj}`;}
  // obj가 문자열일 때
  if(typeof obj === 'string'){return `"${obj}"`;}
  // obj가 배열일 때
  if(Array.isArray(obj)){
    const newArr = obj.map(el => {
      return stringifyJSON(el);
    });
    return `[${newArr}]`;
  // obj가 객체일 때
  }else{
    let newObj = '';
    for(let key in obj){
      if(obj[key] === undefined || typeof obj[key] === 'function'){continue;}
      else{
        newObj = newObj + `${stringifyJSON(key)}:${stringifyJSON(obj[key])},`;
      }
    }
    return `{${newObj.slice(0, -1)}}`;
  }

};

 

 

 

📌  재귀를 이용해 JSON.stringify( ) 메서드를 구현해보며 알게된 점

 

JSON.stringify( )는 정말 모~든 것을 문자열로 바꿔준다.

코드를 구현한 걸 보면 알겠지만, 숫자 타입, boolean 타입, null 타입, 문자열 타입, 배열과 객체까지 문자열로 반환한다.

원시타입은 해당 타입에 " " 큰 따옴표를 씌워주면 그만이었다.

※문자열 타입은 해당 문자열에 따옴표 한번 더 씌우기 주의※

 

 

💚  배열과 객체   -->  객체타입이 문제였다 ^^

 

 

01  배열은 문자열과 합쳐지면 없어지기 일쑤

02  객체는 [object Object]를 출력하기 일쑤

 

일단, 배열과 객체 내에 있는 요소나 키-값 쌍들은 재귀함수를 써서 모두 문자열로 바꿔주고,

배열 리터럴( [ ] )과 객체 리터럴( { } )도 값을 반환하기 직전에 씌워주면 그만이었다.

문제는, 빈 배열이나 빈 객체를 처리하는 방식이었다. 이걸 해결하면서 알게된 점이 많다.

 

 

💚  일단 첫 번째, 빈 배열은 배열의 요소에 ( 요소가 없긴하지만 ) 아무리 undefined를 입혀도 빈배열이다.

 

----------------------------------------------

 

 

 

 

 

 

-----------------------------------------------

 

 

 

 

-----------------------------------------------

 

 

 

 

 

stringifyJSON( )함수에 빈 배열을 담아 호출하더라도 빈 배열이 그대로 나오는 걸 확인할 수 있다.

배열은 이렇게 map을 통해 모든 요소값에 접근하여 stringifyJSON( ) 함수를 입혀 모두 문자열로 변환해, 새로운 배열에 담아줬다.

새로운 배열은 마지막에 `[ ${  } ]` 틀을 씌워줌으로써 배열 자체도 문자열로 변환해주었다.

 

 

 

 

💚  자 두번째, 빈 객체는 for~in문을 거치지 않는다 !! 키 값이 없기때문에 접근 조차 불가하다 

 

 

 

 

 

 

 

 

 

 

 

------------------------------------------------

 

 

 

 

 

 

 

 

 

 

 

지금 for~in문 안에서 빈 객체 아무 반응 없는 거 보이시나여,,,

for~in문은 빈 객체를 실행하지 않는다는 걸 알 수 있다 !!! 

모든 키-값 쌍을 거치는 for~in문을 PASS하고 바로 '{ }'를 리턴해야함을 예상할 수 있다.

 

또한 객체는 배열처럼 map과 같은 메소드도 없어서 직접 "키-값 형식"과 "쉼표"까지 만들어 붙여야 한다.

따로 빈 문자열이 할당된 새로운 변수를 선언해주고, 해당 변수에 " 키 : 값 , " 세트를 계속해서 더해줬다.

이렇게 모두 더해서 만들어진 변수는 마지막에 쉼표 하나를 더 달고 나온다. 이를 slice(0, -1)로 간단히 제거해준다.

정리된 변수는 마지막에 `{ ${  } }` 틀을 씌워줌으로써 객체 자체도 문자열로 변환해주었다.

 

 

 

📌  느낀 점

 

재귀를 써야한다는 강박에 싸여, 어떻게 하지?!...어떻게 하지?!?! 초조해했었다.

함수를 직접 만들고 호출하는 방식이 아직 익숙하지 않다. 이 함수... 써도 되는걸까?  하는 스스로에 대한 믿음도 부족하고 ㅋㅋㅋ

console.log 무한으로 찍어보고 코드도 다시 구성해보면서 두려움이 많이 줄었다.

뇌에 익도록 자주 연습해야겠다.

 

 

 

 

반응형

댓글