Coding/Today I Learned (148)

07
22

1. Stack

사막여우 '스택'이 쌓여있다. 넘어지지 않고 사막여우들이 내려오려면 어떻게 해야할까?

  • 우리가 주로 사용하는 'stack'을 쌓다 라는 말을 생각해 보면 쉽게 알 수 있다.

우리 팀 나서스 20분에 스택 700개, 그는 신이야...!

  • 스택은 자료를 받아와 마지막에 받아온(가장 최근에 들어온) 자료부터 빠져나간다.
  • 우리는 이미 스택을 잘 사용하고 있다. Array 같은 거 말이다. 일상생활에서는 페이지 앞, 뒤로 가기 기능이 있다.
  • 주로 push, pop, top(가장 상단의 데이터를 보여줌), size(얼마나 데이터가 쌓였는지 보여줌)를 사용한다.

2. Queue

게임에서도 '큐'형식으로 줄을 선다. 게임을 하기전에도 줄을 서서 입장하고, 들어 가서도 또 줄을 선다! 질서의 민족!

  • 우리가 주로 사용하는 'Queue'를 잡다 라는 말을 생각해 보면 쉽게 알 수 있다.

ex) 큐 돌려놓고 화장실 가라 빨리 시작하게

  • 큐는 데이터를 순서대로 쌓아 들어온 순서대로 빠져나온다.
  • 일상생활의 줄 서기, 프린터의 작동원리 등으로 볼 수 있다.
  • 주로 push, shift, size를 사용한다.

3. 자료구조를 문제에 적용하는 나의 태도

  • 대부분 알고리즘 문제에 주로 사용된다.
  • 스택과 큐의 특징을 이용하여 문제를 푸는 것이지, 꼭 직접적으로 사용할 필요는 없다.
  • 주로 스택과 큐 둘 다 배열을 잘 사용하며, 배열에 유리한 메서드들을 이용해 데이터를 가공한 후 스택과 큐의 특징처럼 저장소를 사용해 문제를 해결하는 형식이 많다.
문제를 무조건적으로 많이 풀어 보아야 한다. 이미 스택과 큐의 특징은 우리 모두 잘 알고 있을 것이다.
하지만 어떻게 문제에 접근해야 하는가? 에 대한 부분이 매우 시간이 오래 걸린다.
가장 빠른 왕도는 다양한 문제를 접해보고 생각의 범위를 넓이는 것이라고 한다.
요즘 꽤나 공부할 양이 말도 안 되게 늘어서 고통받고 있지만 질질 끌려다니면서 어떻게든 해내고 있는 것 같다.
어떻게든 되겠지, 죽기밖에 더 하겠어
COMMENT
 
07
21

계속 보면 어지럽습니다. 그만 보세요. 재귀함수도 그렇습니다!

1. 재귀 함수?

  • 재귀 함수는 자기 자신을 다시 리턴하는 재귀 함수를 가지는 자기 자신을 다시 리턴하는 재귀 함수를 가지는 자기 자신을 다시 리턴하는 재귀 함수를 가지는 자기 자신을 다시 리턴하는 재귀 함수를 가지는...
  • 자기 자신을 다시 리턴하는 함수이다.
  • 이게 무슨 의미인가?
    • 반복문과 똑같이 작동한다.
    • 반복문처럼 '조건'을 가지고 그 조건에 맞으면 함수를 끝내게 된다.
    • 가독성이 다른 반복의 코드보다 좋다.

2. 예시

  • 한동안 우리를 한참 괴롭히던 피보나치 함수의 재귀 함수 버전이다.
function fibonacci(num) {
  if(num === 0) {
    return 0;
  } else if(num === 1) {
    return 1; // 앞의 if와 else if로 탈출 조건을 만들어 주었다.
  } else {
    num = fibonacci(num - 2) + fibonacci(num - 1) // 우리가 원하는 답을 다시  num에 넣는다.
    return num;
  }
}
  • 반복문 버전보다 훨씬 간단하다.
  • 하지만 효율적이지는 않다. 계속해서 함수를 불러오기 때문에 스택에 무리가 간다.

3. 재귀 함수를 어떻게 쓸 수 있을까?

입력값과 출력 값을 확인한다.

  • 어떤 입력을 받아서 출력을 하는지를 정확히 알아야 함수가 리턴하는 값이 다시 자신으로 들어와 작동할 수 있는지를 알아야 한다.

문제를 쪼개서 생각한다.

  • 입력값을 기준으로 경우의 수를 생각해 본다.
  • 원하는 답으로 가기 위해 한 단계씩 진행되는 과정을 생각해 본다.

탈출 지점 만들기

  • 재귀 함수를 돌다가 원하는 답이 리턴되는, 즉, 가장 작은 단위로 해결된 결과를 리턴한다.
  • 이를 base case라고 한다.

문제를 계속 쪼개어 준다.

  • 더 작은 단위로 문제를 쪼개어 준다. 재귀함수를 탈출하지 못하고 돌 때마다 해결해야 할 문제가 계속 줄어드는 것이다.
  • 이를 recursive case라고 한다.
대충은 알겠지만 계속 사용해 보아야 부족함 없이 쓸 수 있을 것 같다. 재귀 함수는 반복문으로 사용할 수 도 있는데 이것도 생각을 해 보아야 할 문제이다.
COMMENT
 
07
20

1. 문제의 발단

  • 지금도 계속 헷갈리고 있는 재귀함수를 사용하기 위해 일반적으로 사용되는 탬플릿을 외운다
  • 아직 문제를 계속 풀고 있어서 다른 블로깅은 하지 못 할것 같다.
function 재귀함수(처음 입력받거나, 아까 받은 값) {

let [head, ...tail] = arr; // 배열의 가장 앞의 arr[0]를 head, 나머지 요소를 배열안에 tail로 담는다.

	if('탈출 조건') {
		return '마지막에 리턴하게 될 답'
	} else {
		return 재귀함수(다시 매게변수로 넘겨줄 값)
	}
 }
COMMENT
 
07
19

1. class

  • 구성이 비슷한 여러 개의 객체를 만들려고 할 때 사용하는 ''blueprint"가 된다.
  • 예를 들어, 게임 캐릭터의 스킬을 정리해 놓은 리스트를 만들려고 한다.
const Garrosh = {
	passiveSkill : 'Armor Up',
    q : 'Groundbreaker',
    w : 'Bloodthirst',
    e : 'Wrecking Ball',
}

const Artanis = {
	passiveSkill : 'Shiield Overload',
    q : 'Blade Dash',
    w : 'Twin Blades',
    e : 'Phase Prism',
}

const ...
  • 이런 식으로 만들다가는 끝이 없을 것이다.
  • 그렇기 때문에 class를 이용한 객체를 만들 수 있는 생성자를 만들 것이다.
class Hero {
	constructor(passiveSkill, q, w, e) { //constructor를 하나 만들어서 매개변수들을 정해준다.
		this.passiveSkill = passiveSkill;
        	this.q = q;
        	this.w = w;
        	this.e = e;
	}
}

const Nova = new Hero('Permanent Cloak', 'Snipe', 'Pinning Shot', 'Holo Decoy');

// Nova === Hero {
//	  passiveSkill : 'Permanent Cloak',
//    q : 'Snipe',
//    w : 'Pinning Shot',
//    e : 'Holo Decoy',
// }
  • 이는 ES6 문법에서부터 적용된다. 과거의 방법인 함수를 만드는 방법도 있다.
function Hero(passiveSkill, q, w, e) { // 첫번째 글자는 대문자로 쓴다.
	this.passiveSkill = passiveSkill;
    this.q = q;
    this.w = w;
    this.e = e;
}

const Diablo = new Hero('Black Soulstone', 'Shadow Charge', 'Fire Stomp', 'Overpower');

// Diablo === Hero {
//	  passiveSkill : 'Black Soulstone',
//    q : 'Shadow Charge',
//    w : 'Fire Stomp',
//    e : 'Overpower',
// }
  • 위의 class와 똑같이 작동하게 된다. 이렇게 간단하게 계속 캐릭터 정보를 입력할 수 있다.
  • 즉, 엄청난 재사용성을 가지게 된다.
  • 함수와 같은 모든 타입의 데이터도 넣을 수 있다.
  • 이렇게 생성된 객체들을 'instances'라고 한다.

2. prototype

  • 이때, 생성자를 만들면 생성된 자식 object에는 'prototype'이 생성된다. 만들지 않아도 자동으로 생긴다.
  • 간단하게 '유전자'라고 생각하면 된다. 부모가 자식에게 물려주는 것이기 때문이다. 그래서 위의 예시에 Hero에 prototype에 키와 값을 주면 모든 자식에게 영향을 주게 된다.
Hero.prototype.gameTitle = 'Heroes of the Storm'

// Nova.gameTiltle === 'Heroes of the Storm'
// Diablo.gameTitle === 'Heroes of the Storm'
  • 이렇게 숨겨진 prototype에는 우리가 매번 사용하던 기본 함수들이(ex: length, sort 등등) 이미 저장되어 있다.
  • 우리가 평상시에 한 자료를 만들 때 그 타입에 따라 const arr = [1, 2, 3, 4,]로 만들지만, const arr = new Array(1, 2, 3, 4,)로도 만들 수 있다. 똑같은 방식이다. 말하자면, 위에서 보았던 Hero와 Array는 똑같은 역할을 하게 되는 것이다!
  • 그러므로, Array에 prorotype에 있던 각각의 기본 함수들을 그대로 새로 만든 arr에서도 사용할 수 있게 된다.
  • 이를 그대로 응용하면, 우리는 새로운 기본 함수를 Array.prototype.funcA = function() {...}과 같은 식으로 만들어 줄 수 도 있다!

3. OOP

 객체지향 프로그래밍의 주요 콘셉트이다.

  1. 캡슐화(Encapsulation)
    • 데이터를 어떠한 기능이 동작하면 조작할 수 있도록 연결하는 것.
    • 데이터를 일부러 은닉시키기도 한다.
  2. 추상화(Abstraction)
    • 내부 기능은 복잡하게 되어 있을지 몰라도, 우리가 보는 환경에는 단순하게 하여 사용자로 하여금 이용을 편하게 할 수 있게 한다.
    • 옛날에 만들었던 계산기를 생각해 보자. 겉으로 보기에는 사칙연산의 혼합이 가능하거나 소수점 계산이 가능하더라도 생긴 건 불가능한 계산기와 똑같고, 단순하게 숫자와 연산자로 이루어진 모습이다.
  3. 상속(Inheritance)
    • 말 그대로 상속. 부모의 속성과 특징을 자식에게 물려주는 것이다. 위의 예시로 보았듯이, 부모가 가지고 있던 속성을 자식에게 줄 수 있다. 공통되는 부분을 가직 자식 객체들의 똑같은 부분을 계속 적어줄 필요가 없다.
  4. 다양성(Polymorphism)
    • 상속받은 자식들 중에 하나에만 다른 속성을 추가하거나 수정하고 싶을 때는 필요한 함수만, 혹은 속성만 뽑아서 수정하면 된다. 각각 하나하나 따로 수정을 해 줄 필요가 없다.
COMMENT