자료구조란?
대량의 데이터를 효율적으로 관리할 수 있는 데이터의 구조
코드 상에서 데이터를 효율적으로 처리하기 위해 데이터 특성에 따라 체계적으로 데이터를 구조화해야 하며, 어떤 데이터 구조를 사용하느냐에 따라 코드의 효율이 달라질 수 있다.
예시 1. 우편번호: 5자리 우편번호로 국가의 기초구역을 제공
👉🏻 5자리 우편번호에서 앞 3자리는 시, 군, 자치구를 표기, 뒤 2자리는 일련번호로 구성
예시 2. 학생 관리: 학년, 반, 번호를 학생에게 부여해서 학생부를 관리
👉🏻 XX학년, X반, X번 학생
만약 위와 같은 관리 기법이 없다면, 5자리 수를 모두 확인해야 하고 3000명의 학생 중 특정 학생을 찾기 위해 전체 학생부를 모두 훑어야 한다.
즉 수많은 데이터들을 추가하고, 읽어오고, 제거해야 할 때 효율적으로 관리를 해야 시간을 줄일 수 있기 때문에 자료구조가 필요하다.
데이터들이 일렬로 쭉 저장되어 있는 형태
데이터가 트리 형태로 저장되어 있다고 생각하고 사용하는 자료구조
데이터를 나열하고, 각 데이터를 인덱스에 대응하도록 구성한 데이터 구조
(파이썬에서는 리스트 타입이 배열 기능을 제공)
같은 종류의 데이터를 효율적으로 관리하기 위해!
같은 종류의 데이터를 순차적으로 저장하기 위해!
🔥 장점
🔥 단점
데이터를 제한적으로 접근할 수 있는 구조
한쪽 끝에서만 자료를 넣거나 뺄 수 있는 구조
가장 나중에 쌓은 데이터를 가장 먼저 빼낼 수 있는 데이터 구조
큐(Queue) | 스택(Stack) |
---|---|
F.I.F.O | L.I.F.O |
First In First Out | Last In First Out |
스택은 LIFO(Last In, Fisrt Out) 또는 FILO(First In, Last Out) 데이터 관리 방식을 따른다.
LIFO: 마지막에 넣은 데이터를 가장 먼저 추출하는 데이터 관리 정책
FILO: 처음에 넣은 데이터를 가장 마지막에 추출하는 데이터 관리 정책
주요 기능
push(): 데이터를 스택에 넣기 pop(): 데이터를 스택에서 꺼내기
🔥 장점
🔥 단점
스택은 단순하고 빠른 성능을 위해 사용되므로, 보통 배열 구조를 활용해서 구현하는 것이 일반적이다.
구조 : 줄을 서는 행위와 유사
가장 먼저 넣은 데이터를 가장 먼저 꺼낼 수 있는 구조
음식점에서 가장 먼저 줄을 선 사람이 제일 먼저 음식점에 입장하는 것과 동일
FIFO(First-In, First-Out) 또는 LILO(Last-In, Last-Out) 방식으로 스택과 꺼내는 순서가 반대
멀티 태스킹을 위한 프로세스 스케쥴링 방식을 구현하기 위해 많이 사용된다.
트리: 노드(node)와 브랜치(branch)를 이용해서, 사이클을 이루지 않도록 구성한 데이터 구조
Node
: 트리에서 데이터를 저장하는 기본 요소 (데이터와 다른 연결된 노드에 대한 Branch 정보 포함)
Root Node
: 트리 맨 위(최 상단)에 있는 노드
Level
: 최상위 노드를 Level 0으로 하였을 때, 하위 Branch로 연결된 노드의 깊이를 나타냄
Parent Node
: 어떤 노드의 다음 레벨에 연결된 노드
Child Node
: 어떤 노드의 상위 레벨에 연결된 노드
Leaf Node (Terminal Node)
: Child Node가 하나도 없는 노드
Sibling (Brother Node)
: 동일한 Parent Node를 가진 노드
Depth
: 트리에서 Node가 가질 수 있는 최대 Level (깊이를 나타냄)
🌲 이진 트리(Binary Tree): 노드의 최대 브랜치가 2개인 트리
🌲 이진 탐색 트리(Binary Search Tree): 이진 트리에 다음과 같은 추가적인 조건이 있는 트리
공통점: 힙과 이진 탐색 트리는 모두 이진 트리이다. (자식 노드가 최대 2개가 있는 트리 구조)
차이점:
🔥 장점
🔥 단점
가장 기본적인 자료구조인 Array 자료구조는, 논리적 저장 순서와 물리적 저장 순서가 일치한다. 따라서 인덱스(index)로 해당 원소(element)에 접근할 수 있다. 그렇기 때문에 찾고자 하는 원소의 인덱스 값을 알고 있으면 Big-O(1)에 해당 원소로 접근할 수 있다. 즉 random access 가 가능하다는 장점이 있는 것이다.
하지만 삭제 또는 삽입의 과정에서는 해당 원소에 접근하여 작업을 완료한 뒤(O(1)), 또 한 가지의 작업을 추가적으로 해줘야 하기 때문에, 시간이 더 걸린다. 만약 배열의 원소 중 어느 원소를 삭제했다고 했을 때, 배열의 연속적인 특징이 깨지게 된다. 즉 빈 공간이 생기는 것이다. 따라서 삭제한 원소보다 큰 인덱스를 갖는 원소들을 shift해줘야 하는 비용(cost)이 발생하고 이 경우의 시간 복잡도는 O(n)가 된다. 그렇기 때문에 Array 자료구조에서 삭제 기능에 대한 time complexity 의 worst case 는 O(n)이 된다.
삽입의 경우도 마찬가지이다. 만약 첫번째 자리에 새로운 원소를 추가하고자 한다면 모든 원소들의 인덱스를 1 씩 shift 해줘야 하므로 이 경우도 O(n)의 시간을 요구하게 된다.
💎 요약
이 부분에 대한 문제점을 해결하기 위한 자료구조가 linked list 이다. 각각의 원소들은 자기 자신 다음에 어떤 원소인지만을 기억하고 있다. 따라서 이 부분만 다른 값으로 바꿔주면 삭제와 삽입을 O(1) 만에 해결할 수 있는 것이다.
하지만 Linked List 역시 한 가지 문제가 있다. 원하는 위치에 삽입을 하고자 하면 원하는 위치를 Search 과정에 있어서 첫번째 원소부터 다 확인해봐야 한다는 것이다. Array 와는 달리 논리적 저장 순서와 물리적 저장 순서가 일치하지 않기 때문이다. 이것은 일단 삽입하고 정렬하는 것과 마찬가지이다. 이 과정 때문에, 어떠한 원소를 삭제 또는 추가하고자 했을 때, 그 원소를 찾기 위해서 O(n)의 시간이 추가적으로 발생하게 된다.
결국 linked list 자료구조는 search 에도 O(n)의 time complexity 를 갖고, 삽입, 삭제에 대해서도 O(n)의 time complexity 를 갖는다. 그렇다고 해서 아주 쓸모없는 자료구조는 아니기에, 우리가 학습하는 것이다. 이 Linked List 는 Tree 구조의 근간이 되는 자료구조이며, Tree 에서 사용되었을 때 그 유용성이 드러난다.
💎 요약
둘의 차이점을 정리하자면 이렇다.
배열(Array) | 연결 리스트(Linked List) |
---|---|
정적 자료구조 | 동적 자료구조 |
미리 크기를 정해 놓음 | 크기를 정할 필요가 없음 |
연속된 메모리 주소를 할당 받음 | 연속된 메모리 주소를 할당 받지 않음 |
접근, 탐색 용이 | 추가, 삭제 용이 |
index 존재 | Node 존재 |
📍 출처
주홍철, [면접을 위한 CS 전공지식 노트]
penjee
prepare_frontend_interview
Interview_Question_for_Beginner
wikipedia, https://en.wikipedia.org/wiki/Linked_list
📍 참고하면 좋을 사이트
컴퓨터의 힙(Heap)
간략 설명! 배열(Array)과 연결 리스트(Linked List)에 대해서 알아보자! - 차이점과 시간복잡도, 활용 사례까지