Java
List
dev-rootable
2024. 5. 8. 15:05
❓ List 인터페이스란
중복을 허용하면서 저장 순서가 유지되는 컬렉션을 구현하는 데 사용되는 인터페이스
✔ Thread-safe
멀티스레드 프로그래밍에서 여러 스레드가 공유 자원을 사용할 때, 작업 후 원하는 결과가 나오는 것을 보장하는 성질
이를 위해 임계 영역, Lock 등을 사용하여 한 작업의 결과가 일관성 있게 반영되도록 한다. 하지만 Thread-unsafe보다 속도가 느리기 때문에 멀티스레드 환경이 아니라면 굳이 사용할 필요가 없다.
✅ 특징
- 저장 순서가 유지됨
- 중복 저장 허용
- 배열과 마찬가지로 index로 요소 접근
- 동적인 자료형 크기
- 요소 사이에 빈 공간을 허용하지 않아 삽입/삭제마다 배열 이동이 일어난다.
📚 Methods
Method | Description |
void add(int index, Object element) boolean addAll(int index, Collection c) |
지정된 위치(index)에 객체(element) 또는 컬렉션에 포함된 객체들을 추가 |
void clear() | 모든 요소 삭제 |
Object get(int index) | 지정된 위치(index)에 있는 객체를 반환 |
int indexOf(Object o) | 지정된 객체의 위치(index)를 반환한다. (List의 첫 번째 요소부터 순방향으로 찾는다.) |
int lastIndexOf(Object o) | 지정된 객체의 위치(index)를 반환한다. (List의 마지막 요소부터 역방향으로 찾는다.) |
ListIterator listIterator() ListIterator listIterator(int index) |
List의 객체에 접근할 수 있는 ListIterator를 반환 |
Object remove(int index) | 지정된 위치(index)에 있는 객체를 삭제하고 삭제된 객체를 반환한다. |
Object set(int index, Object element) | 지정된 위치(index)에 객체(element)를 저장 |
void sort(Comparator c) | 지정된 비교자(comparator)로 List를 저장 |
List subList(int fromIndex, int toIndex) | 지정된 범위(fromIndex ~ toIndex)에 있는 객체를 반환 |
📌 ArrayList
배열을 이용하여 만든 리스트
✅ 특징
- 자동 Resizable
- 데이터 저장 순서 유지
- 중복 허용
- 단방향 포인터 구조로 자료에 대한 순차적 접근에 강점 있어 조회가 빠름
- 삽입/삭제가 느리다. 단, 순차적으로 삽입/삭제하는 경우에는 가장 빠르다.
✅ 시간복잡도
작업 | Method | 시간복잡도 |
add at last index | add() | O(1) |
add at given index | add(index, value) | O(N) |
remove by index | remove(index) | O(N) |
remove by value | remove(value) | O(N) |
get by index | get(index) | O(1) |
search by value | indexOf(value) | O(N) |
📌 LinkedList
노드(객체)를 연결하여 리스트처럼 만든 컬렉션(배열 아님)
✅ 특징
- 데이터의 중간 삽입/삭제가 빈번할 경우 빠른 성능을 보장
- 데이터 개수만큼 메모리를 할당하므로, 메모리 관리가 편리
- 특정 인덱스를 찾기 위해서는 전체 데이터를 순차검색하므로, O(n)의 시간이 소요됨 (검색 성능 🔽)
- 객체로 데이터를 다루기 때문에 적은 양의 데이터만 사용할 경우 배열에 비해 차지하는 메모리가 큼
- 자바의 LinkedList는 Doubly LinkedList(양방향 포인터 구조)로 이루어져 있다.
- LinkedList는 리스트 용도 이외에도 Stack, Queue, Tree 등의 자료구조의 근간이 된다.
📌 Vector
ArrayList의 구형 버전으로 차이는 Thread-Safe다.
구버전 자바와 호환성을 위해 남겨두었으며 잘 쓰이진 않는다.
만일 협업에서 컬렉션 동기화가 필요하면 Collections.synchronizedList() 메서드를 이용해 ArrayList를 동기화
처리하여 사용한다.
📌 Stack
한쪽 끝에서만 자료를 넣거나 뺄 수 있는 구조로 LIFO(Last In First Out) 구조로 동작
이러한 구조는 보통 '뒤로 가기', '실행 취소(undo)', 'stack memory'에서 활용된다.
장점은 후출선입인 만큼 직전의 데이터를 빠르게 갖고 올 수 있다는 것이다. 또한 균형성 검사를 할 수 있기 때문에 수식, 괄호
등의 검사에서도 활용된다.
'동적 할당'을 전제로 하며, Vector 클래스의 하위 클래스이기 때문에 잘 사용되지 않는다. (대신 ArrayDeque 사용)
✅ 주요 메서드
주요 메서드는 데이터를 추가하는 push와 삭제하는 pop이다.
여기서 search라는 메서드는 스택 내부 배열의 인덱스를 반환하는 것이 아니라 Stack의 상단으로부터 몇 번째에 위치하는지를 반환하는 것이다. 즉, 거리 개념이라고 보면 된다.
References:
https://st-lab.tistory.com/161
https://st-lab.tistory.com/169
https://st-lab.tistory.com/173