💡 이번에 배운 내용
- Section4. 사람과 기계가 모두 쉽고 빠르게 접근 가능한 Web App을 만들 수 있다.
- Unit1. [자료구조/알고리즘] 기초: 컴퓨터 공학의 기본인 자료구조에 대해 이해하고, 이해한 자료구조를 바탕으로 알고리즘 문제를 직접 구현하며 학습한다.
이번 유닛은 이해하는 데도 오래걸리고 문제푸는데도 정말 쉽지 않았던 유닛이었다. 물론 지난번 네트워크 유닛도 어려운 건 매한가지였지만, 이번 유닛은 문제를 풀려니까 더욱 쉽지않았다. 개념을 간신히 이해했어도 문제로 푸니 또 느낌이 색다르기도 했고 내가 이해한 내용이 실제 적용과 달라 해매기도 했기 때문이다. 여기에 놓쳤거나 미숙했던 자바스크립트 문법이 있다면 더 어려웠다.
나는 의사코드 작성이 너무 오래 걸리고 여기에 집착하는 게 아닌가 하는 생각이 들었다. 앞으로 의사코드를 좀 더 단순하게, 빨리 작성하여 코드로 옮기는 습관을 들여야 겠다. 그리고 미숙했던 자바스크립트 실수는 가급적 안 하도록 코딩테스트 경험치를 계속 잘 쌓아야 겠다!
후🤯 이번 유닛도 간신히 블로깅에 성공하였다!
자료구조, 스택 stack, 큐 queue, LIFO, FIFO, 트리 Tree, 노드 Node, 루트 Root, 레벨 level, 깊이 depth, 이진 트리 binary tree, 이진 탐색 트리 binary search tree, 트리 순회, 전위 순회, 중위 순회, 후위 순회, 그래프 graph, 정점 vertex, 간선 edge, 가중치 그래프 weighted graph, 무방향 그래프 undirected graph, 방향 그래프 directed graph, 인접 행렬, 너비 우선 탐색 BFS, 깊이 우선 탐색 DFS
이번 학습에 앞서 미리 알고있어야 하는 개념에 대해 정리해 보았다.
복습도 해볼겸 그 목록을 아래와 같이 정리했다.
이번 챕터에서는 중요 표시된 챕터 외에도 모든 챕터가 정말 중요하다고 볼 수 있다. 중요 표시된 챕터는 이해하기 어려웠거나 더 중요하다고 생각하여 표시했다.
자료구조란 여러 데이터의 묶음을 저장하고, 사용하는 방법을 정의한 것이다. 모든 프로그래밍 언어는 다 다르긴 하지만 내장된 자료구조가 존재한다.
여기서 데이터(data)는 실생활을 구성하고 있는 모든 값으로 그림, 영상, 사람의 이름, 나이, 전화번호 등 거의 모든 것들이 예시가 된다. 그러나 이 데이터가 의미를 가지기 위해서는 활용할 수 있도록 가공을 해야 한다.
때문에 데이터를 사용하려면 그 목적에 맞게 형태를 구분하고, 분류해야 한다.
많은 자료구조를 알아두면, 문제를 해결해야 할 때 적합한 자료구조를 적용하여 문제를 좀 더 빠르고 효율적으로 해결할 수 있다. 특정 문제를 해결하는 데에 적합한 자료구조를 찾아 데이터를 정리한다면 상황에 맞는 코드를 작성하는 데 도움이 된다.
위에 말했듯이 이런 데이터들을 효율적으로 다루기 위한 방법들을 자료구조라고 한다.
여기에는 많은 자료구조가 있으며, 이 자료구조는 알고리즘 테스트를 위해 알아야 한다.
이번 유닛에서는 가장 많이 사용하는 자료구조 다음 네 가지를 중점적으로 학습한다.
Stack은 데이터(data)를 순서대로 쌓는 구조로 양동이에 접시를 하나씩 쌓는 모양새를 생각하면 편하다.
그 모양새를 생각해 봤을 때 그 특징을 정리하자면 다음과 같다.
LIFO(Last In First Out) 또는 FILO(First In Last Out)
먼저 들어간 데이터는 제일 나중에 나오고, 마지막에 있는 데이터가 먼저 나오는 선입후출, 후입선출의 구조를 가지고 있다.
이 스택은 조회가 필요하지 않아 데이터를 저장하고 검색하는 프로세스가 매우 빠르며, 최상위 블록인 top에서 데이터를 저장하고 검색하면 된다는 장점이 있다.
데이터는 push, pop을 사용해 하나씩 넣고 뺄 수 있다.
Stack에 데이터를 넣는 것을 'PUSH', 데이터를 꺼내는 것을 'POP'이라고 하며 이 데이터를 하나씩 넣고, 꺼낸다. 한꺼번에 여러 개를 넣거나 뺄 수 없다.
입출력 방향이 같다.
Stack은 입출력 방향이 하나로 서로 같다. 그러므로 만약 입출력 방향이 여러 개라면 Stack 자료구조라고 볼 수 없다.
저장되는 데이터는 유한하고 정적이어야 한다.
그 이유는 콜 스택의 작동원리를 보면 알 수 있다. 콜 스택(Call Stack)은 스택 자료 구조를 사용했으며 함수가 실행되면 그 데이터가 스택에 저장된다. 그리고 함수가 종료될 때 이 스택에 쌓인 모든 변수가 지워진다. 스택은 데이터가 하나씩 입출력되고 처음 실행한 데이터가 가장 마지막에 나간다. 만약 함수 안의 데이터들이 동적이라면 컴파일 시간을 계산하기 힘들지만, 정적이라면 이 스택의 데이터를 활용해 컴파일 시간을 결정할 수 있다.
따라서 스택 구조를 활용하기 위해 데이터들은 유한하고 정적이어야 한다. 처음 들어간 데이터는 모든 데이터가 삭제될 때까지 기다려야 하기 때문이다.
스택의 크기는 제한되어 있다.
힙(heap)에 비해 스택의 크기는 제한되어 있다. 만약 스택의 크기를 초과하여 데이터가 저장된다면 스택 오버플로(Stack Overflow)에러가 생긴다. 대부분의 언어에는 스택에 저장할 수 있는 값의 크기가 제한되어 있다.
대표적인 예로 브라우저의 뒤로 가기, 앞으로 가기 기능 구현이 있다.
설명을 위해 현재페이지, 이전페이지 기록이 쌓이는 Prev Stack, 다음페이지 기록이 쌓이는 Next Stack이 있다고 가정하자.
작동 원리는 다음과 같다.
큐(Queue)는 대기행렬 이라는 뜻으로 줄을 서서 기다리듯이 데이터를 입력된 순서대로 처리한다.
그 특징은 아래와 같다.
FIFO (First In First Out) 또는 LILO(Last In Last Out)
먼저 들어간 데이터가 제일 처음에 나오는 선입선출의 구조를 가지고 있습니다.
제일 첫 번째 있는 데이터부터 차례대로 나오게 됩니다.
데이터는 하나씩 넣고 뺄 수 있습니다.
Queue 자료구조는 데이터가 아무리 많이 있어도 하나씩 데이터를 넣고, 뺍니다. 한꺼번에 여러 개를 넣거나 뺄 수 없습니다.
Queue에 데이터를 넣는 것을 'enqueue', 데이터를 꺼내는 것을 'dequeue'라고 합니다.
두 개의 입출력 방향을 가지고 있습니다.
입력과 출력의 방향이 고정되어 있으며, 두 곳으로 접근이 가능합니다. Queue 자료구조는 데이터의 입력, 출력 방향이 다릅니다. 만약 입출력 방향이 같다면 Queue 자료구조라고 볼 수 없습니다.
버퍼
컴퓨터 장치들 사이에서 데이터(data)를 주고받을 때, 각 장치 사이에 존재하는 속도의 차이나 시간 차이를 극복하기 위해 임시 기억 장치의 자료구조로 Queue를 사용한다. 이것을 통틀어 버퍼(buffer)라고 합니다. 빠른 CPU는 작업을 처리하여 큐에 저장한 뒤 다른 작업을 처리하고, 상대적으로 느린 다른 장치들은 큐에 있는 이벤트를 순차적으로 처리한다. 이때 버퍼(buffer)를 사용한다.
프린터 작업 Queue
프린트를 출력하면 그 문서는 인쇄 작업 큐에 들어간다. 버퍼와 같은 원리로 속도가 빠른 CPU가 인쇄 명령을 큐에 넣으면 프린터는 그 큐에 들어온 문서를 순서대로 인쇄한다.
동영상 스트리밍(유튜브 등)
동영상을 시청할 때, 동영상을 정상적으로 재생하기 위해 데이터를 Queue에 모아 두었다가 동영상을 재생하기에 충분한 양의 데이터가 모였을 때 동영상을 재생한다.
Tree는 이름 그대로 나무를 거꾸로 뒤집어 놓은 듯한 모습으로 마치 뿌리가 뻗어나가는 모양을 하고 있다. 단방향 그래프이고, 계층적 자료구조이다.
특징은 다음과 같다.
또한 이 트리 구조는 기본 트리 구조에 몇 가지 추가적인 조건에 따라 여러 종류로 나뉜다.
이중에 대표적으로 이진 트리(binary tree)와 이진 탐색 트리(binary search tree)가 있다.
이진 트리(Binary tree)는 자식 노드가 왼쪽 자식 노드, 오른쪽 자식 노드 이렇게 최대 두 개로 구성된 트리를 의미한다.이진 트리는 이진 탐색 트리, 이진 힙 구현에 사용된다.
또한 이진 트리는 몇 가지 조건에 따라 다음과 같이 나뉜다.
이진 탐색 트리란 이진 탐색(binary search)과 연결 리스트(linked list)를 결합한 이진트리를 의미한다. 이진 탐색의 탐색 능력을 유지하면서 빈번한 자료 입력과 삭제를 가능하게끔 고안되었다.
이진 탐색 트리의 특징은 아래와 같다.
이진 탐색 트리는 기존 이진 트리보다 탐색이 빠르다. 이진 탐색 트리의 탐색은 트리의 높이가 n(height)일 때 o(n)의 복잡도를 가진다.
이진 탐색 트리의 탐색 과정은 다음과 같다.
트리의 모든 노드를 한 번씩 탐색하는 것을 트리 순회라고 한다. 이 순회 방법은 전위 순회, 중위 순회, 후위 순회 이렇게 3가지가 있다. 루트, 즉 '위'를 언제 순회하느냐에 따라 전위, 중위, 후위로 이해하면 쉽다.
이진 탐색 트리의 구조에 비해 순회 방법은 복잡한데, 트리 구조 전체를 탐색해야 하기 때문이다.
모든 노드를 방문하기 위해서는 일정한 조건이 필요하고, 위의 각 순회 방법에서 살펴봤듯이 특정 목적에 따라 순회 방법을 적절히 사용해야 한다.
그래프는 여러개의 점들이 서로 복잡하게 연결되어 있는 관계를 표현한 자료구조로 마치 거미줄처럼 여러 개의 점들이 선으로 이어져 있는 복잡한 네트워크망과 같은 모습을 가지고 있다.
각 점을 정점(vertex)이라고 하며, 정점 사이를 이은 선을 간선(edge)이라고 한다.
직접적인 관계가 있다면 두 정점 사이를 이어주는 간선이 있으며 간접적인 관계는 몇 개의 정점과 간선에 걸쳐 이어진다.
위에서 살펴본 용어대로 두 정점을 바로 이어주는 간선이 있다면 이 두 정점은 인접하다고 한다.
인접 행렬은 이 정점들의 인접 관계를 간선이 있는지 없는지로 표시한 행렬로 2차원 배열의 형태이다.
만약 A라는 정점과 B라는 정점이 이어져 있다면 1(true), 이어져 있지 않다면 0(false)으로 표시한다. 가중치 그래프라면 1 대신 관계에서 의미 있는 값을 저장한다.
아래의 그림을 예시로 인접 행렬을 만들어보려고 한다.
ABC 각각을 0,1,2 인덱스라고 가정하고 [출발지][도착지]
순으로 2차원 배열로 나타낸다고 가정하자.
[0][2] === 1
[1][0] === 1
[1][2] === 1
[2][0] === 1
[0][2] === 1
, [2][0] === 1
이렇게 된다는 것을 알 수 있다.예시의 인접 행렬의 최종 모습을 2차원 배열로 나타내면 아래와 같다.
const matrix=[
[0, 0, 1],
[1, 0, 1],
[1, 0, 0]
];
이 인접 행렬은 두 정점 사이의 관계를 빠르게 확인할 수 있으며 가장 빠른 경로를 찾을 때 사용된다.
인접 리스트는 각 정점이 어떤 정점과 인접하는지 리스트의 형태로 표현한다.
각 정점별로 하나씩 리스트가 있으며 각 정점과 인접한 다른 정점을 담고 있다.
위 인접 행렬에서의 예시를 리스트로 표현하면 다음과 같다.
A->C->null
B->A->C->null
B->C->A->null
C->A->null
이 그래프를 인접 리스트로 표현한다면 우선수위는 필수 사항은 아니다.
그러나 만약 우선 순위가 더 중요하다면 큐(queue)나 힙(heap) 등의 자료구조를 사용하는 것이 더 좋다. 때에 따라 상황에 맞는 자료구조를 사용하도록 한다.
그래프에서 탐색은 하나의 정점에서 시작해 그래프의 모든 정점들을 한 번씩 탐색하는 것이다. 그래프는 정렬이 되어 있지 않기 때문에 원하는 정점을 찾으려면 한 번씩 모든 정점을 탐색해야 한다.
이 그래프의 탐색 방법에는 대표적으로 너비 우선 탐색(BFS: Breadth-First Search)과 깊이 우선 탐색(DFS: Depth-First Search)이 있다.
각각의 장단점을 파악하여 경우에 따라 맞는 방법을 사용한다.
너비 우선 탐색은 가까운 정점부터 모두 탐색한 후, 그 다음 떨어져 있는 정점을 순서대로 탐색한다.
주로 두 정점 사이의 최단 경로를 찾을 때 사용하며, 만약 경로를 하나씩 전부 탐색하면 최악의 경우에는 모든 경로를 다 살펴봐야 한다.
깊이 우선 탐색은 하나의 경로를 끝까지 탐색한 후, 도착지가 아니라면 다음 경로로 넘어가 탐색한다.
하나의 경로를 마지막까지 확인한 다음이나, 가는 길이 아님을 미리 체크한 후 더이상 갈 수 없다면 바로 다음 경로로 넘어간다.
최단 경로와 상관없이 경로를 먼저 발견할 수도 있으며, BFS보다 탐색 시간은 조금 오래걸리는 편이다. 마찬가지로 최악의 경우 모든 경로를 다 살펴봐야 한다.
1. DFS와 BFS의 장단점은?
복습하며 작성할 것
2. 그래프가 굉장히 크다면 DFS와 BFS중 어떤 탐색 기법을 사용해야 할까?
복습하며 작성할 것
3. 그래프의 규모가 작고, depth가 얕다면 어떤 탐색 기법을 사용해야 할까?
복습하며 작성할 것
4. 자료구조를 눈으로 확인하기 좋은 사이트
아래 사이트들은 자료구조를 그림과 애니메이션으로 쉽게 확인할 수 있다.