[S4]Chapter1.[자료구조/알고리즘] 기초

박현석·2022년 11월 25일
1

코드스테이츠

목록 보기
29/40
post-thumbnail

자료구조

  • 자료구조란 여러 데이터의 묶음을 저장하고, 사용하는 방법을 정의한 것
  • 데이터를 정해진 규칙 없이 저장하거나, 하나의 구조로만 정리하고 활용하는 것보다 데이터를 체계적으로 정리하여 저장해두는 게, 데이터를 활용하는 데 있어 훨씬 유리합니다.

자료구조의 분류

무수한 상황의 예시

  • 번호를 다 알지 않아도, 이름을 아는 것만으로 전화를 할 수 있는 방법은 무엇이 있을까?
  • 웹 브라우저에서 뒤로 / 앞으로 가는 방법은 무엇이 있을까?
  • 게임 매칭을 잡을 때, 수많은 사람을 통제하는 방법엔 무엇이 있을까? ...등등
  • 무수한 상황에서 데이터를 효율적으로 다룰 수 있는 방법을 모두 모아, 자료구조라는 이름을 붙였습니다.

자료구조의 특징

  • 특정한 상황에 놓인 문제를 해결하는 데에 특화
  • 많은 자료구조를 알아두면, 어떠한 상황이 닥쳤을 때 적합한 자료구조를 빠르고 정확하게 적용하여 문제를 해결할 수 있습니다.

Stack과 Queue

Stack

  • Stack은 쌓다, 쌓이다, 포개지다 와 같은 뜻을 가지고 있습니다.
  • 데이터(data)를 순서대로 쌓는 자료구조

Stack 구조

  • 골목을 자료구조 Stack, 자동차는 데이터(data)로 비유할 수 있습니다.
  • 자료구조 Stack의 특징은 입력과 출력이 하나의 방향으로 이루어지는 제한적 접근에 있습니다.
  • 이런 Stack 자료구조의 정책을 LIFO(Last In First Out) 혹은 FILO(First In Last Out)이라고 부르기도 합니다.
  • Stack에 데이터를 넣는 것을 'PUSH', 데이터를 꺼내는 것을 'POP'이라고 합니다.

Stack의 특징

1. LIFO(Last In First Out)

  • 먼저 들어간 데이터는 제일 나중에 나오는 후입선출의 구조를 가지고 있습니다.
1) 1, 2, 3, 4를 스택에 차례대로 넣습니다.
stack.push(데이터)
---------------------------
1 <- 2 <- 3 <- 4
---------------------------
들어간 순서대로, 1번이 제일 먼저 들어가고 4번이 마지막으로 들어가게 됩니다.2) 스택이 빌 때까지 데이터를 전부 빼냅니다.
stack.pop()
---------------------------
---------------------------
4, 3, 2, 1
제일 마지막에 있는 데이터부터 차례대로 나오게 됩니다.
  • 이러한 특성으로 인해 스택 구조는 조회가 필요하지 않으므로, 해당 자료구조를 사용해 데이터를 저장하고 검색하는 프로세스가 매우 빠르며, 최상위 블록에서 데이터를 저장하고 검색하면 된다는 장점

2. 데이터는 하나씩 넣고 뺄 수 있습니다.

  • Stack 자료구조는 데이터가 아무리 많이 있어도 하나씩 데이터를 넣고, 뺍니다. 한꺼번에 여러 개를 넣거나 뺄 수 없습니다.

3. 하나의 입출력 방향을 가지고 있습니다.

  • Stack 자료구조는 데이터의 입출력 방향이 같습니다. 만약, 입출력 방향이 여러 개라면 Stack 자료구조라고 볼 수 없습니다.

4. 저장되는 데이터는 유한하고 정적이어야 합니다.

5. 스택의 크기는 제한되어 있습니다.

  • 힙(heap)에 비해 스택의 크기가 제한되어 있으므로, 스택 오버플로(Stack Overflow) 같은 에러가 자주 발생합니다. 대부분의 언어는 스택에 저장할 수 있는 값의 크기가 제한되어 있습니다.

예제

Queue

  • 큐(Queue)는 줄을 서서 기다리다, 대기행렬 이라는 뜻을 가지고 있습니다.
  • 톨게이트를 Queue 자료구조, 자동차는 데이터(data)로 비유할 수 있습니다.
  • 가장 먼저 진입한 자동차가 가장 먼저 톨게이트를 통과합니다.

Queue의 구조

  • 자료구조 Queue는 Stack과 반대되는 개념으로, 먼저 들어간 데이터(data)가 먼저 나오는 FIFO(First In First Out) 혹은 LILO(Last In Last Out) 을 특징

Queue의 특징

1. FIFO (First In First Out)

1) 1, 2, 3, 4를 큐에 차례대로 넣습니다.
						queue.enqueue(데이터)
출력 방향 <---------------------------< 입력 방향
				     1 <- 2 <- 3 <- 4
				<---------------------------<
들어간 순서대로, 1번이 제일 먼저 들어가고 4번이 마지막으로 들어가게 됩니다.2) 큐가 빌 때까지 데이터를 전부 빼냅니다.
						queue.dequeue(데이터)
출력 방향 <---------------------------< 입력 방향
				<---------------------------<
1, 2, 3, 4
제일 첫 번째 있는 데이터부터 차례대로 나오게 됩니다.
  • 먼저 들어간 데이터가 제일 처음에 나오는 선입선출의 구조를 가지고 있습니다.

2. 데이터는 하나씩 넣고 뺄 수 있습니다.

  • Queue 자료구조는 데이터가 아무리 많이 있어도 하나씩 데이터를 넣고, 뺍니다. 한꺼번에 여러 개를 넣거나 뺄 수 없습니다.

3. 두 개의 입출력 방향을 가지고 있습니다.

  • Queue 자료구조는 데이터의 입력, 출력 방향이 다릅니다. 만약 입출력 방향이 같다면 Queue 자료구조라고 볼 수 없습니다.

예제

  • 속도의 차이나 시간 차이를 극복하기 위해 임시 기억 장치의 자료구조로 Queue를 사용 이것을 버퍼(buffer)라고 한다.

Tree와 Graph

Tree

  • 자료구조 Tree는 이름 그대로 나무의 형태
  • 그래프의 여러 구조 중 단방향 그래프의 한 구조로, 하나의 뿌리로부터 가지가 사방으로 뻗은 형태가 나무와 닮아 있다고 해서 트리 구조
  • 데이터를 순차적으로 나열시킨 선형 구조가 아니라, 하나의 데이터 아래에 여러 개의 데이터가 존재할 수 있는 비선형 구조
  • 트리 구조는 계층적으로 표현이 되고, 아래로만 뻗어나가기 때문에 사이클(cycle)이 없습니다.

Tree의 구조와 특징

  • 트리 구조는 루트(Root) 라는 하나의 꼭짓점 데이터를 시작으로 여러 개의 데이터를 간선(edge)으로 연결
  • 각 데이터를 노드(Node)
  • 두 개의 노드가 상하 계층으로 연결되면 부모/자식 관계

깊이 (depth)

  • 루트로부터 하위 계층의 특정 노드까지의 깊이(depth)를 표현할 수 있다.
  • 루트 노드는 지면에 있는 것처럼 깊이가 0입니다. 위 그림에서 루트 A의 depth는 0이고, B와 C의 깊이는 1입니다. D, E, F, G의 깊이는 2입니다.

레벨(Level)

  • 같은 깊이를 가지고 있는 노드를 묶어서 레벨(level)로 표현할 수 있다.
  • depth가 0인 루트 A의 level은 1입니다. depth가 1인 B와 C의 level은 2입니다. D, E, F, G의 레벨은 3입니다. 같은 레벨에 나란히 있는 노드를 형제 노드(Sibling Node) 라고 합니다.

높이(Height)

  • 리프 노드를 기준으로 루트까지의 높이(height)를 표현할 수 있다.
  • 리프 노드와 직간접적으로 연결된 노드의 높이를 표현하며, 부모 노드는 자식 노드의 가장 높은 height 값에 +1한 값을 높이로 가집니다.
  • 트리 구조의 높이를 표현할 때에는 각 리프 노드의 높이를 0으로 놓습니다. 위 그림에서 H, I, E, F, J의 높이는 0입니다. D와 G의 높이는 1입니다. B와 C의 높이는 2입니다. 이때 B는 D의 height + 1 을, C는 G의 height + 1 을 높이로 가집니다. 따라서, 루트 A의 높이는 3입니다.

서브 트리(Sub tree)

  • root에서 뻗어 나오는 큰 트리의 내부에, 트리 구조를 갖춘 작은 트리를 서브 트리 라고 부릅니다.
  • (D, H, I)로 이루어진 작은 트리도 서브 트리이고, (B, D, E)나 (C, F, G, J)도 서브 트리입니다.

용어정리

  • 노드(Node) : 트리 구조를 이루는 모든 개별 데이터
  • 루트(Root) : 트리 구조의 시작점이 되는 노드
  • 부모 노드(Parent node) : 두 노드가 상하관계로 연결되어 있을 때 상대 적으로 루트에서 가까운 노드
  • 자식 노드(Child node) : 두 노드가 상하관계로 연결되어 있을 때 상대적으로 루트에서 먼 노드
  • 리프(Leaf) : 트리 구조의 끝 지점이고, 자식 노드가 없는 노드

예제

Binary Search Tree

이진 트리(Binary tree)

  • 이진 트리(Binary tree)는 자식 노드가 최대 두 개인 노드들로 구성된 트리
  • 이진 트리는 자료의 삽입, 삭제 방법에 따라 정 이진 트리(Full binary tree), 완전 이진 트리(Complete binary tree), 포화 이진 트리(Perfect binary tree)로 나뉩니다.
  • 정 이진 트리(Full binary tree) : 각 노드가 0개 혹은 2개의 자식 노드를 갖습니다.
  • 포화 이진 트리(Perfect binary tree) : 정 이진 트리이면서 완전 이진 트리인 경우입니다. 모든 리프 노드의 레벨이 동일하고, 모든 레벨이 가득 채워져 있는 트리입니다.
  • 완전 이진 트리(Complete binary tree) : 마지막 레벨을 제외한 모든 노드가 가득 차 있어야 하고, 마지막 레벨의 노드는 전부 차 있지 않아도 되지만 왼쪽이 채워져야 합니다.

이진 탐색 트리(Binary Search Tree)

  • 이진 탐색 트리란 이진 탐색(binary search)과 연결 리스트(linked list)를 결합한 이진트리
  • 이진 탐색의 효율적인 탐색 능력을 유지하면서도, 빈번한 자료 입력과 삭제를 가능하게끔 고안됐습니다.

이진 탐색 트리 특징

  • 각 노드에 중복되지 않는 키(Key)가 있습니다.
  • 루트노드의 왼쪽 서브 트리는 해당 노드의 키보다 작은 키를 갖는 노드들로 이루어져 있습니다.
  • 루트노드의 오른쪽 서브 트리는 해당 노드의 키보다 큰 키를 갖는 노드들로 이루어져 있습니다.
  • 좌우 서브트리도 모두 이진 탐색 트리여야 합니다.
  • 즉 이진 탐색 트리(Binary Search Tree)는 모든 왼쪽 자식의 값이 루트나 부모보다 작고, 모든 오른쪽 자식의 값이 루트나 부모보다 큰 값을 가지는 특징

Tree Traversal

  • 트리를 순회할 수 있는 세 가지 방법은 전위 순회, 중위 순회, 후위 순회

전위 순회 (preorder traverse)

중위 순회 (inorder traverse)

후위 순회 (postorder traverse)

순회 방식을 나누는 이유

  • 일정 조건에 의해 설계된 트리 구조는 자식 노드에 대한 조건이 명확하다면 원하는 값을 쉽게 찾아낼 수 있게 되지만, 트리 구조 전체를 탐색할 때는 이야기가 조금 달라지기 때문
  • 모든 노드를 방문하기 위해서는 일정한 조건이 필요하고, 트리 구조를 유지보수하거나 특정 목적을 위해서도 순회 방법에 대한 정의는 필수적으로 필요

Graph

  • 여러개의 점들이 서로 복잡하게 연결되어 있는 관계를 표현한 자료구조

Graph의 구조

  • 직접적인 관계가 있는 경우 두 점 사이를 이어주는 선이 있습니다.
  • 간접적인 관계라면 몇 개의 점과 선에 걸쳐 이어집니다.
  • 하나의 점을 그래프에서는 정점(vertex)이라고 표현하고, 하나의 선은 간선(edge)이라고 합니다.

Graph의 표현 방식

1. 인접 행렬

  • 두 정점을 바로 이어주는 간선이 있다면 이 두 정점은 인접
  • 인접 행렬은 서로 다른 정점들이 인접한 상태인지를 표시한 행렬로 2차원 배열의 형태로 나타냅니다.
  • A라는 정점과 B라는 정점이 이어져 있다면 1(true), 이어져 있지 않다면 0(false)으로 표시한 일종의 표
  • A의 진출차수는 1개 입니다: A —> C
    - [0][2] === 1
  • B의 진출차수는 2개 입니다: B —> A, B —> C
    - [1][0] === 1
    - [1][2] === 1
  • C의 진출차수는 1개입니다: C —> A
    - [2][0] === 1

인접 행렬은 언제 사용할까?

  • 한 개의 큰 표와 같은 모습을 한 인접 행렬은 두 정점 사이에 관계가 있는지, 없는지 확인하기에 용이합니다.
    - 예를 들어, A에서 B로 진출하는 간선이 있는지 파악하기 위해선 0 번째 줄의 1 번째 열에 어떤 값이 저장되어있는지 바로 확인할 수 있습니다.
  • 가장 빠른 경로(shortest path)를 찾고자 할 때 주로 사용됩니다.

2. 인접 리스트

  • 리스트에 담겨진 정점들을 우선 순위별로 정렬할 수 있습니다. 우선 순위가 없다면, 연결된 정점들을 단순하게 나열한 리스트가 됩니다.
  • 우선 순위를 다뤄야 한다면 더 적합한 자료구조(ex. queue, heap)를 사용하는 것이 합리적입니다. 따라서 보통은 중요하지 않습니다. (언제나 예외는 있습니다.)

인접 리스트는 언제 사용할까?

  • 메모리를 효율적으로 사용하고 싶을 때 인접 리스트를 사용합니다.
    - 인접 행렬은 연결 가능한 모든 경우의 수를 저장하기 때문에 상대적으로 메모리를 많이 차지합니다.

알아둬야 할 Graph 용어들

-정점 (vertex): 노드(node)라고도 하며 데이터가 저장되는 그래프의 기본 원소입니다.

  • 간선 (edge): 정점 간의 관계를 나타냅니다. (정점을 이어주는 선)
  • 인접 정점 (adjacent vertex): 하나의 정점에서 간선에 의해 직접 연결되어 있는 정점을 뜻합니다.
  • 가중치 그래프 (weighted Graph): 연결의 강도(추가적인 정보, ex. 서울-부산으로 가는 거리 등)가 얼마나 되는지 적혀져 있는 그래프를 뜻합니다.
    -비가중치 그래프 (unweighted Graph): 연결의 강도가 적혀져 있지 않는 그래프를 뜻합니다.
  • 무(방)향 그래프 (undirected graph): 앞서 보았던 내비게이션 예제는 무(방)향 그래프입니다. 서울에서 부산으로 갈 수 있듯, 반대로 부산에서 서울로 가는 것도 가능합니다. 하지만 단방향(directed) 그래프로 구현된다면 서울에서 부산을 갈 수 있지만, 부산에서 서울로 가는 것은 불가능합니다(혹은 그 반대). 만약 두 지점이 일방통행 도로로 이어져 있다면 단방향인 간선으로 표현할 수 있습니다.
  • 진입차수 (in-degree) / 진출차수 (out-degree): 한 정점에 진입(들어오는 간선)하고 진출(나가는 간선)하는 간선이 몇 개인지를 나타냅니다.
  • 인접 (adjacency): 두 정점 간에 간선이 직접 이어져 있다면 이 두 정점은 인접한 정점입니다.
  • 자기 루프 (self loop): 정점에서 진출하는 간선이 곧바로 자기 자신에게 진입하는 경우 자기 루프를 가졌다 라고 표현합니다. 다른 정점을 거치지 않는다는 것이 특징입니다.
  • 사이클 (cycle): 한 정점에서 출발하여 다시 해당 정점으로 돌아갈 수 있다면 사이클이 있다고 표현합니다. 내비게이션 그래프는 서울 —> 대전 —> 부산 —> 서울 로 이동이 가능하므로, 사이클이 존재하는 그래프입니다.

BFS와 DFS

  • 두 정점 사이의 최단 경로를 찾을 때 사용

  • 한 정점에서 시작해서 다음 경로로 넘어가기 전에 해당 경로를 완벽하게 탐색할 때 사용
profile
선한 영향력을 주는 사람

0개의 댓글