ArrayList·HashSet·TreeSet·HashMap·TreeMap
오늘 자바의 자료구조인 컬렉션 프레임워크(ArrayList, HashSet, TreeSet, HashMap, TreeMap)를 공부했다. 수많은 메서드가 있지만, 가장 많이 쓰이는 위주로 정리해 보았다.
| 구분 | 구현 클래스 | 특징 | 중복 허용 | 정렬/순서 |
|---|---|---|---|---|
| List | ArrayList | 인덱스로 관리하는 동적 배열 | ✅ | 입력 순서 유지 |
| Set | HashSet | 집합 개념, 빠른 검색 속도 | ❌ | ❌ |
| Set | TreeSet | 이진 트리 구조의 집합 | ❌ | 값 기준 정렬 |
| Map | HashMap | Key-Value 쌍으로 저장 | Key ❌ | ❌ |
| Map | TreeMap | Key-Value 쌍 + 자동 정렬 | Key ❌ | 키 기준 정렬 |
| 메서드 | 설명 |
|---|---|
add(E e) | 요소 추가 |
remove(Object o) | 요소 삭제 |
contains(Object o) | 포함 여부 확인 (있으면 true) |
size() | 요소 개수 반환 |
clear() | 모든 요소 삭제 |
isEmpty() | 비어있으면 true |
List<String> list = new ArrayList<>();
list.add("Apple"); // [Apple]
list.add("Banana"); // [Apple, Banana]
list.remove("Apple"); // [Banana]
list.contains("Banana"); // true
list.size(); // 1
list.isEmpty(); // false
list.clear(); // []
Set<String> set = new HashSet<>();
set.add("Apple");
set.add("Apple"); // 중복 → 무시됨
set.size(); // 1
Set은 순서가 없어 인덱스 개념이 없으므로 아래 메서드는 List에서만 사용할 수 있다.
| 메서드 | 설명 |
|---|---|
get(int index) | 해당 인덱스의 요소 반환 |
set(int index, E e) | 해당 인덱스의 요소를 교체 |
indexOf(Object o) | 요소의 첫 번째 인덱스 반환 (없으면 -1) |
List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Cherry");
list.get(0); // "Apple"
list.set(1, "Blueberry"); // [Apple, Blueberry, Cherry]
list.indexOf("Cherry"); // 2
list.indexOf("Mango"); // -1 (없는 요소)
키와 값을 쌍으로 저장하는 구조.
| 메서드 | 설명 |
|---|---|
put(K key, V value) | Key-Value 추가 (키 중복 시 값 덮어쓰기) |
get(Object key) | 키에 해당하는 값 반환 (없으면 null) |
remove(Object key) | 키에 해당하는 쌍 삭제 |
containsKey(Object key) | 키 존재 여부 확인 |
keySet() | 모든 키를 Set으로 반환 |
values() | 모든 값을 Collection으로 반환 |
Map<String, Integer> map = new HashMap<>();
map.put("홍길동", 90);
map.put("이순신", 85);
map.put("홍길동", 95); // 키 중복 → 값 95로 덮어쓰기
map.get("홍길동"); // 95
map.get("강감찬"); // null (없는 키)
map.containsKey("이순신"); // true
map.keySet(); // [홍길동, 이순신]
map.values(); // [95, 85]
map.remove("이순신"); // 이순신 쌍 삭제
// keySet()으로 전체 순회
for (String key : map.keySet()) {
System.out.println(key + " : " + map.get(key));
}
정렬이 보장되기 때문에 범위 검색과 최솟값/최댓값 조회가 가능.
| 메서드 | 설명 |
|---|---|
first() / firstKey() | 가장 작은 값(키) 반환 |
last() / lastKey() | 가장 큰 값(키) 반환 |
subSet(from, to) / subMap(from, to) | from 포함, to 미포함 |
headSet(to) / headMap(to) | to 미만의 요소 반환 |
tailSet(from) / tailMap(from) | from 이상의 요소 반환 |
// TreeSet 예제
TreeSet<Integer> treeSet = new TreeSet<>();
treeSet.add(30); treeSet.add(10); treeSet.add(50); treeSet.add(20);
// 자동 정렬됨 → [10, 20, 30, 50]
treeSet.first(); // 10 (최솟값)
treeSet.last(); // 50 (최댓값)
treeSet.subSet(10, 40); // [10, 20, 30] (40 미포함)
treeSet.headSet(30); // [10, 20] (30 미포함)
treeSet.tailSet(20); // [20, 30, 50]
// TreeMap 예제
TreeMap<String, Integer> treeMap = new TreeMap<>();
treeMap.put("banana", 2); treeMap.put("apple", 5); treeMap.put("cherry", 1);
// 키 기준 알파벳 정렬 → {apple=5, banana=2, cherry=1}
treeMap.firstKey(); // "apple"
treeMap.lastKey(); // "cherry"
treeMap.subMap("apple", "cherry"); // {apple=5, banana=2}
HashSet / HashMap은 해시 함수로 데이터 위치를 바로 찾아가기 때문에 O(1) 로 매우 빠르다.
반면 TreeSet / TreeMap은 데이터를 넣을 때마다 기존 데이터들과 비교해 정렬된 위치를 탐색하므로 O(log n) 의 비용이 발생한다.
| 컬렉션 | 검색/삽입/삭제 | 정렬 | 사용 기준 |
|---|---|---|---|
| HashSet / HashMap | O(1) | ❌ | 기본 선택 — 속도 우선 |
| TreeSet / TreeMap | O(log n) | ✅ | 정렬이 꼭 필요할 때 |
정렬이 꼭 필요한 경우가 아니라면, Hash 계열을 사용하는 것이 기본 !
Set은 수학의 집합과 동일한 개념이라 합집합, 교집합, 차집합 연산을 메서드 하나로 처리할 수 있다.
| 연산 | 메서드 | 설명 |
|---|---|---|
| 합집합 (A ∪ B) | addAll(Collection c) | 다른 컬렉션의 요소를 모두 추가 |
| 교집합 (A ∩ B) | retainAll(Collection c) | 다른 컬렉션과 공통된 요소만 남김 |
| 차집합 (A - B) | removeAll(Collection c) | 다른 컬렉션에 있는 요소를 모두 제거 |
⚠️ 이 메서드들은 원본 Set을 직접 수정하므로 원본을 보존하려면 새로운 Set에 복사한 뒤 사용.
Set<Integer> A = new HashSet<>(Arrays.asList(1, 2, 3, 4, 5));
Set<Integer> B = new HashSet<>(Arrays.asList(3, 4, 5, 6, 7));
// 합집합 (A ∪ B) → [1, 2, 3, 4, 5, 6, 7]
Set<Integer> union = new HashSet<>(A);
union.addAll(B);
System.out.println(union);
// 교집합 (A ∩ B) → [3, 4, 5]
Set<Integer> intersection = new HashSet<>(A);
intersection.retainAll(B);
System.out.println(intersection);
// 차집합 (A - B) → [1, 2]
Set<Integer> difference = new HashSet<>(A);
difference.removeAll(B);
System.out.println(difference);
Set<Integer> A = new HashSet<>(Arrays.asList(5, 3, 1, 4, 2));
Set<Integer> B = new HashSet<>(Arrays.asList(3, 4, 5, 6, 7));
Set<Integer> union = new HashSet<>(A);
union.addAll(B);
System.out.println(union); // HashSet → 순서 무작위
System.out.println(new TreeSet<>(union)); // TreeSet → 자동 정렬: [1, 2, 3, 4, 5, 6, 7]
List<String> playlist = new ArrayList<>();
playlist.add("노래 A");
playlist.add("노래 B");
playlist.add("노래 A"); // 중복 OK
System.out.println(playlist.get(0)); // 노래 A
Set<String> visited = new HashSet<>();
visited.add("Seoul");
visited.add("Tokyo");
visited.add("Seoul"); // 중복 → 무시됨
System.out.println(visited.size()); // 2
Map<String, Integer> score = new HashMap<>();
score.put("홍길동", 90);
score.put("이순신", 85);
System.out.println(score.get("홍길동")); // 90