`List`는 순서가 있는 원소들의 집합을 나타내는 자료구조입니다. `List`는 중복 원소를 허용하며 각 원소가 인덱스를 가지는 순서가 있는 컬렉션입니다. 자바에서 `List`는 `java.util.List` 인터페이스를 구현한 다양한 클래스들로 제공됩니다.
List의 특징
1. 중복 원소 허용: `List`는 같은 값을 여러 번 저장할 수 있습니다.
2. 순서 보장: `List`는 원소들이 추가된 순서대로 저장되며, 각 원소는 인덱스를 가지고 있어 순차적으로 접근할 수 있습니다.
3. 인덱스를 통한 접근: `List`는 인덱스를 통해 특정 원소를 빠르게 조회할 수 있습니다.
4. 동적 크기: `List`는 동적으로 크기가 늘어나고 줄어듭니다. 즉, 배열과 달리 크기를 미리 정의할 필요가 없습니다.
List를 구현한 주요 클래스들
1. ArrayList: 가장 일반적으로 사용되는 `List` 구현체로, 내부적으로 배열을 사용하여 데이터를 저장합니다. 검색이 빠르지만 원소의 추가 및 삭제에서는 성능이 떨어질 수 있습니다.
2. LinkedList: 링크드 리스트를 기반으로 한 구현체로, 원소의 추가와 삭제가 빠르지만, 랜덤 접근에서 성능이 떨어집니다.
3. Vector: `ArrayList`와 비슷하지만 동기화가 지원되는 클래스입니다. 현재는 거의 사용되지 않으며, `ArrayList`가 대체하고 있습니다.
4. Stack: `List`의 한 종류로, LIFO(Last-In-First-Out) 구조를 제공합니다. 주로 스택 자료구조로 사용됩니다.
List의 주요 메서드
- add(E e): 리스트의 끝에 원소를 추가합니다.
- get(int index): 지정된 인덱스의 원소를 반환합니다.
- remove(int index): 지정된 인덱스의 원소를 제거합니다.
- size(): 리스트의 크기(원소 개수)를 반환합니다.
- contains(Object o): 리스트에 지정된 원소가 존재하는지 확인합니다.
- isEmpty(): 리스트가 비어 있는지 확인합니다.
- clear(): 리스트의 모든 원소를 제거합니다.
자바에서 List 사용 예시
1. ArrayList 사용 예시
`ArrayList`는 배열을 기반으로 한 `List` 구현체입니다. 원소를 추가하거나 조회할 때 효율적이지만, 중간에 원소를 삽입하거나 삭제할 때는 성능이 떨어질 수 있습니다.
import java.util.*;
public class ArrayListExample {
public static void main(String[] args) {
// ArrayList 생성
List<String> list = new ArrayList<>();
// 원소 추가
list.add("apple");
list.add("banana");
list.add("cherry");
// 원소 출력
System.out.println("List: " + list);
// 인덱스로 원소 조회
System.out.println("Element at index 1: " + list.get(1)); // "banana"
// 원소 삭제
list.remove(0); // "apple" 삭제
System.out.println("List after removal: " + list);
// 리스트 크기
System.out.println("Size of list: " + list.size());
// 리스트에 원소가 포함되어 있는지 확인
if (list.contains("cherry")) {
System.out.println("List contains cherry");
}
// 리스트 비우기
list.clear();
System.out.println("List after clearing: " + list);
}
}
출력 예시:
List: [apple, banana, cherry]
Element at index 1: banana
List after removal: [banana, cherry]
Size of list: 2
List contains cherry
List after clearing: []
2. LinkedList 사용 예시
`LinkedList`는 링크드 리스트를 기반으로 한 `List` 구현체입니다. 원소의 삽입과 삭제는 빠르지만, 특정 인덱스에 접근하려면 리스트를 처음부터 끝까지 순차적으로 탐색해야 하므로 랜덤 접근 성능이 떨어집니다.
import java.util.*;
public class LinkedListExample {
public static void main(String[] args) {
// LinkedList 생성
List<String> list = new LinkedList<>();
// 원소 추가
list.add("apple");
list.add("banana");
list.add("cherry");
// 원소 출력
System.out.println("List: " + list);
// 첫 번째 원소 삭제
list.remove(0); // "apple" 삭제
System.out.println("List after removal: " + list);
// 첫 번째 원소 조회
System.out.println("First element: " + list.get(0)); // "banana"
// 리스트 크기
System.out.println("Size of list: " + list.size());
}
}
출력 예시:
List: [apple, banana, cherry]
List after removal: [banana, cherry]
First element: banana
Size of list: 2
- `LinkedList`는 빠른 삽입과 삭제가 필요한 경우에 유리합니다. 특히, 리스트의 처음이나 끝에서 원소를 추가/삭제하는 성능이 뛰어납니다.
List의 특징 및 장단점
| 특징/구분 | ArrayList | LinkedList |
| 구현 방식 | 내부적으로 배열을 사용 | 내부적으로 이중 연결 리스트를 사용 |
| 검색 성능 | 빠르다 (O(1)) | 느리다 (O(n)) |
| 삽입/삭제 성능 | 중간 삽입/삭제는 느리다 (O(n)) | 삽입/삭제가 빠르다 (O(1)) |
| 사용 사례 | 데이터가 고정되거나 조회가 자주 일어날 때 | 원소의 삽입/삭제가 자주 일어날 때 |
| 메모리 사용 | 더 적은 메모리 사용 (배열 사용) | 더 많은 메모리 사용 ( LinkedList 사용) |
List 사용 시 장점
1. 순서 유지: `List`는 삽입된 순서를 보장하며, 인덱스를 사용해 빠르게 원소를 조회할 수 있습니다.
2. 중복 원소 허용: 동일한 원소를 여러 번 추가할 수 있습니다.
3. 동적 크기 조정: `List`는 크기가 동적으로 조정되므로 원소의 개수를 미리 알지 않아도 됩니다.
List 사용 시 단점
1. 중간 삽입/삭제 성능: `ArrayList`는 중간에 원소를 삽입하거나 삭제할 때 성능이 떨어질 수 있습니다. 반면 `LinkedList`는 삽입/삭제 성능이 우수하지만, 랜덤 접근 성능이 떨어집니다.
2. 메모리 사용: `LinkedList`는 두 개의 포인터(앞, 뒤)를 저장해야 하므로 더 많은 메모리를 사용합니다.
결론
- ArrayList는 빠른 랜덤 접근이 필요한 경우, 즉 원소를 자주 조회하는 경우에 적합합니다.
- LinkedList는 원소의 삽입과 삭제가 빈번하게 일어나는 경우에 적합합니다. 특히 리스트의 처음이나 끝에서 원소를 추가/삭제할 때 성능이 뛰어납니다.
`List`는 데이터 구조 선택 시 작업의 특성에 따라 선택해야 하며, 자주 조회되는 데이터에는 `ArrayList`를, 삽입/삭제가 자주 일어나는 데이터에는 `LinkedList`를 선택하는 것이 좋습니다.