1:1
의 구조를 가지고 있다.연속적인 메모리 공간에 데이터를 저장한다.
배열의 크기는 생성 시에 정해지며, 불변
이다.
임의 접근(Random Access)이 가능하다.
배열의 크기가 고정되어 있어 배열을 확장하려면 새로운 배열을 생성하고 기존의 데이터를 복사해야 한다.
예를 들어, 주식 차트에 대한 데이터는 중간에 데이터를 새롭게 추가하거나 삭제되는 정보가 아니며, 날짜별 주식 가격을 차례대로 저장해야 하는 데이터라서 순서를 보장해주는 자료구조인 배열을 사용하는 것이 좋다.
연속적이지 않은 메모리 공간에 데이터를 저장한다.
크기가 동적
이다.
리스트는 크게 배열 기반의 ArrayList와 연결 리스트 기반의 LinkedList로 구분된다.
데이터의 추가, 삭제가 배열에 비해 유연하지만, 특정 인덱스의 데이터에 접근하기 위해서는 처음부터 순차적으로 탐색해야 할 수도 있어 접근 속도가 느리다.
내부적으로 데이터를 배열로 관리한다.
데이터의 추가 또는 삭제 작업은 기존의 위치한 데이터들의 이동이 발생하여 상대적으로 느리다.
배열과 다르게 동적으로 크기를 조절할 수 있다. (동적 할당)
데이터가 노드(Node)
형태로 저장되며, 각 노드는 다음 노드를 가리키는 참조(주소)
를 가진다.
데이터의 추가 또는 삭제 작업이 빠르다.
특정 데이터에 접근하기 위해서는 Head
노드부터 순차적으로 탐색해야 하므로 접근 속도가 느리다.
각 노드가 다음 노드의 참조(주소)를 변수(Point)에 저장해야 하기 때문에 추가적인 메모리 공간이 필요하다.
LinkedList 종류
1. 단방향 연결 리스트
2. 양방향 연결 리스트
3. 양방향 원형 연결 리스트
LIFO(Last In First Out) 구조
데이터를 뒤에서부터 꺼내기 때문에 기존의 위치한 데이터들을 이동할 필요가 없으니 리스트보다는 배열로 구현하는게 좋다.
수식계산, 수식 괄호 검사, undo/redo, 웹 브라우저 히스토리, JVM Stack 메모리 등에서 스택이 사용된다.
자바의 Stack은 Vector
클래스를 상속받아 Thread-Safe하다는 특징이 있다.
List
인터페이스를 상속받는 컬렉션 프레임워크의 일종
컬렉션 프레임워크가 나오기 전에 가변 개수의 배열이 필요할 때 사용했지만, 현대에는 성능 상 사용하지 않고 ArrayList
를 사용한다.
ArrayList
와 메서드 구성도 거의 같다.멀티 스레드 환경에서의 Vector
의 동기화
ArrayList
와의 차이점은 메서드에 synchronized
키워드의 유무이다.Vector
클래스는 Thread-Safe하다는 특징이 있다.💡 synchronized 키워드
멀티 스레드 환경에서 두 개 이상의 스레드가 하나의 변수에 동시에 접근할 때
Race condition
(경쟁상태)이 발생하지 않도록 잠금을 거는 것
FIFO(First In First Out) 구조
요소의 추가 및 삭제 작업 시 기존의 위치한 데이터들의 이동이 발생하므로 배열보다 연결 리스트로 구현하는게 좋다.
데이터가 들어가는 것을 Enqueue
, 데이터가 나가는 것을 Dequeue
라고 부른다.
front
로 정하여 삭제 연산만 수행하고, 다른 한 쪽은 rear
로 정하여 삽입 연산만 수행한다.자바에서 큐는 이중 연결 리스트로 구현되어 있는 LinkedList
클래스로 초기화 한다.
그래프의 넓이 우선 탐색(BFS), 스케줄링 알고리즘 중 하나인 FCFS(First Come First Served)에서 큐가 사용된다.
선형 큐의 오버플로우 문제를 해결하기 위한 방법 중 하나로, 배열의 끝과 시작이 연결된 형태로 구현된다.
자바의 표준 라이브러리에서는 순환 큐를 구현한 클래스를 제공하지 않는다.
ArrayDeque
클래스가 내부적으로 순환 구조를 사용하여 덱을 구현하므로, 크기가 고정되지 않은 순환 큐의 대안으로 사용할 수 있다.들어간 순서에 상관없이 우선순위가 높은 데이터를 먼저 꺼내기 위해 고안된 자료구조
구현 방식에는 배열, 연결 리스트, 힙이 있고, 그 중 힙 방식은 최악의 경우 시간 복잡도 을 보장하기 때문에 일반적으로 완전 이진트리 형태의 힙
을 이용해 구현한다.
힙
구조로 설계되어 있다.PriorityQueue
클래스를 통해 우선순위 큐를 제공한다.양쪽 끝에서 삽입과 삭제가 가능한 형태의 큐
자바에서 Deque
인터페이스의 구현체인 ArrayDeque
클래스를 사용하여 덱을 구현할 수 있다.
자바의 LinkedList
도 Deque
인터페이스의 구현체이므로 덱을 구현할 수 있다.
ArrayDeque
가 더 효율적이다.LinkedList
가 더 적합할 수 있다.1:N
또는 N:N
의 구조를 가지고 있다.계층 구조
를 표현하기에 적절한 자료구조로 트리
와 그래프
가 대표적인 비선형 자료구조이다.노드(Node)
와 노드를 연결하는 엣지(Edge)
로 구성된 계층적인 자료구조
하나의 루트 노드에서 출발하여 여러 개의 자식 노드를 가질 수 있으며, 각 노드는 다른 자신의 자식 노드를 가질 수 있다.
파일 시스템, 데이터베이스의 인덱싱, DOM 구조 등에서 트리 구조가 사용된다.
트리 관련 용어
💡 기본적으로 트리의 크기가 N일 때, 전체 간선의 개수는 N-1개이다.
트리의 순회
각 노드가 최대 두 개
의 자식 노드를 가지는 형태의 트리
특정한 순서를 따르지 않고, 노드의 배치가 자유롭다.
힙
은 완전 이진 트리의 일종으로, 완전 이진 트리는 부모 노드 밑에 자식 노드가 최대 2개까지 있을 수 있고, 마지막 높이를 제외한 모든 높이에 노드가 완전히 채워져 있는 트리 구조를 말한다.
최대 힙
과 최소 힙
이 있다.이진 트리의 한 종류로, 이진 탐색이 동작할 수 있도록 고안된 효율적인 탐색
이 가능한 자료구조
모든 노드는 왼쪽 자식 노드보다 큰 값, 오른쪽 자식 노드보다 작은 값을 가지는 특징이 있다.
탐색, 삽입, 삭제 등의 연산을 시간에 수행할 수 있어, 대량의 데이터를 효율적으로 관리할 수 있다.
정렬이 되어있는 경우, 효율적인 탐색이 가능하다.
만약 트리의 균형이 한쪽으로 치우쳐진 경우, 최악의 경우 시간 복잡도를 갖게 되고, 이러한 문제(균형)를 개선하기 위해 나온 기법이 레드-블랙 트리(RBT), AVL 트리
이다.
BST
의 삽입, 삭제 연산 과정에서 발생할 수 있는 문제점을 해결하기 위해 만들어졌다.균형
을 재조정하여 탐색 효율성을 보장한다.레드-블랙 트리의 규칙
레드-블랙 트리의 회전 방법은 링크 참고! [래드-블랙 트리 참고]
이진 탐색 트리의 단점을 개선한 스스로 균형을 잡는 트리
균형도
라는 것을 이용하여 삽입 및 삭제 시 균형을 맞춘다.
레드-블랙 트리
보다 더 엄격하게 균형을 잡는다.균형도가 절대값 2미만이면 균형 트리
이고, 2이상이면 불균형 트리
이다.
균형도를 구하기 위해서는 먼저 높이를 구해야 한다.
AVL 트리의 높이 구하기
0
이다.null
인 경우 높이는 -1
로 본다.최대값 + 1
AVL 트리의 균형도 구하기
0
null
인 경우 높이는 -1
로 본다.균형 vs 불균형
LL 문제
(Left-Left)라고 하고, 우측으로 치우친 것은 RR 문제
(Right-Right)라고 한다. 이외에도 같은 원리로 LR 문제
, RL 문제
도 있다.4가지의 불균형 트리의 문제에 따른 각각의 회전 방법은 링크 참고! [AVL 트리 참고]
레드-블랙 트리 vs AVL 트리
RBT
에 비해 상대적으로 적기 때문에 RBT
가 적합할 수 있다.AVL 트리
가 적합하다.노드(정점, Vertex)와 노드를 연결하는 엣지(간선, Edge)로 구성된 자료구조
그래프는 방향성이 있는 방향 그래프
와 방향성이 없는 무방향 그래프
로 나뉜다.
그래프의 간선에는 가중치
를 부여할 수 있고, 가중치를 부여한 그래프를 가중치 그래프
라고 부르며, 보통 거리, 비용, 우선순위 등을 나타내는 데 사용된다.
차수는 한 노드에 인접한 간선의 수를 의미한다.
네트워크 시스템, 소셜 네트워크, 지도의 경로 탐색 등 다양한 분야에서 그래프를 사용한다.
대표적으로 인접 리스트
와 인접 행렬
로 그래프를 표현한다.
그래프의 장점
그래프의 단점
스택
또는 재귀
를 사용한다.큐
를 사용한다.키(Key)를 값(Value)에 매핑하는 구조를 가진 자료구조
F(key) → HashCode → Index → Value
해시 함수
해시 코드
버킷(Bucket)
또는 슬롯(Slot)
평균적으로 시간 복잡도 로 데이터를 빠르게 조회한다.
두 개 이상의 키가 동일한 해시 코드를 가지면 충돌(Collision)이 발생한다.
1. 분리 연결법(Separate Chaining)
각 버킷에 연결 리스트 같은 자료구조를 사용하여, 같은 해시 코드를 가진 항목들을 연결한다.
Java8
의 해시 테이블은 Self-Balancing Binary Search Tree 자료구조를 사용해 Chaining
방식을 구현한다.
이러한 Chaining 방식은 해시 테이블의 확장이 필요없고 간단하게 구현이 가능하며, 손쉽게 삭제할 수 있다는 장점이 있지만, 데이터의 수가 많아지면 동일한 버킷에 Chaining되는 데이터가 많아져 그에 따라 캐시의 효율성이 떨어진다는 단점이 있다.
2. 개방 주소법(Open Addressing)
1. 선형 탐사(Linear Probing)
고정폭
만큼씩 이동하여 차례대로 검색해 비어 있는 버킷에 데이터를 저장한다.2. 이차 탐사(Quadratic Probing)
제곱
으로 저장하는 방식이다.3. 이중 해싱(Double Hashing Probing)
Dummy Space
로 활용되므로, 해시 테이블을 재정리 해주는 작업이 필요하다.