[java] TreeMap
📌 TreeMap?
음.. Map을 공부하다 보니 TreeMap이란 것을 알게되었다. Tree랑 Map이 합쳐지다니 벌써부터 어떤 자료 구조인지 궁금하다. 알아보러 가자
역시 먼저 자바 DOC에서 TreeMap에 대한 설명을 확인해 보자
Treemap은 레드-블랙 트리를 기반으로 한 NavigableMap 구현체이다. 이 맵은 키의 자연 순서대로, 또는 맵 생성시 제공된 Comparator에 따라 정렬된다.
이 구현체는 containsKey, get, put, remove 연산에 대해 log(n) 시간 복잡도를 보장한다.
compareTo와 equals의 일관성을 유지해야한다. ( 두개의 키가 compareTo에 의해 같다고 판정되면, TreeMap 입장에서 이 두 키는 같다고 간주된다.
여기서 레드-블랙 트리라는 새로운 개념이 나오는데 레드-블랙 트리란 균형 잡힌 이진 탐색 트리로, 일정한 규칙을 통해 트리의 균형을 유지하고 효율적인 연산을 보장한다. O(log n)의 성능을 제공한다.
레드-블랙 트리는 내용이 많아. 추후에 따로 포스팅을 해야겠다.
✏️ 생성자
TreeMap()
기본 생성자로, 비어 있는 새로운 TreeMap을 생성한다.
TreeMap( Comparator<? super K> comparator )
주어진 Comparator를 사용하여 키를 정렬하는 새로운 빈 TreeMap을 생성한다.
TreeMap( Map<? extends K, ? extends V> m )
주어진 Map의 모든 항목을 포함하는 새로운 TreeMap을 생성한다.
TreeMap( SortedMap<K, ? extends V> m)
주어진 SortedMap을 복사하고, 그 정렬 순서를 그대로 사용하는 새로운 TreeMap을 생성한다.
📌 TreeMap 메서드
메서드 | 설명 | 반환 값 |
V put(K key, V value) | 주어진 키와 값을 추가하거나, 해당 키가 이미 존재하면 값을 덮어 쓴다. | 이전 값 또는 null |
V get(Object key) | 지정된 키와 연관된 값을 반환한다. | 값 또는 null |
V remove(Object key) | 주어진 키를 삭제하고, 대응되는 값을 반환한다 | 삭제된 값 또는 null |
void clear() | 모든 항목을 삭제한다 | void |
boolean containsKey(Object key) | 주어진 키가 존재하는지 확인한다 | true OR false |
boolean containsValue(Object value) | 주어진 값이 존재하는지 확인한다 | true OR false |
int size() | 트리맵에 포함된 항목의 수를 반환한다 | 항목의 개수 |
boolean isEmpty() | 트리맵이 비어있는지 확인한다 | true OR false |
Set<K> keySet() | 모든 키를 정렬된 순서로 포함하는 Set을 반환한다 | 키들의 집합( Set ) |
Collection<V> values() | 모든 값을 포함하는 Collection을 반환한다. | 값들의 컬렉션 ( Collection ) |
Set<Map.Entry<K, V>> entrySet() | 모든 키-값 쌍을 포함하는 Set을 반환한다. | 키들의 집합 |
K firstKey() | 첫 번째 (가장 작은) 키를 반환한다. | 첫 번쨰 키 |
K lastKey() | 마지막 (가장 큰) 키를 반환한다. | 마지막 키 |
K higherKey(K key) | 주어진 키보다 큰 가장 작은 키를 반환한다. | 키 또는 null |
K lowerKey(K key) | 주어진 키보다 작은 가장 큰 키를 반환한다. | 키 또는 null |
K ceilingKey(K key) | 주어진 키보다 큰 가장 작은 키를 반환한다. | 키 또는 null |
K floorKey(K key) | 주어진 키보다 작은 가장 큰 키를 반환한다. | 키 또는 null |
Map.Entry<K, V> firstEntry() | 주어진 키와 같거나 큰 가장 작은 키를 반환한다. | 첫 번째 엔트리 또는 null |
Map.Entry<K, V> lastEntry() | 주어진 키와 같거나 작은 가장 큰 키를 반환한다. | 마지막 엔트리 또는 null |
Map.Entry<K, V> pollFirstEntry() | 첫 번째 엔트릴를 반환한다 | 삭제된 첫 번쨰 엔트리 |
Map.Entry<K, V> pollLastEntry() | 마지막 엔트리를 반환한다 | 삭제된 마지막 엔트리 |
NavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) | 주어진 범위 내의 엔트리를 포함하는 NavigableMap을 반환합니다. | 부분맵 |
NavigableMap<K, V> headMap(K toKey, boolean inclusive) | 주어진 키까지의 엔트리를 포함하는 NavigableMap을 반환한다. | 부분 맵 |
NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) | 주어진 키부터의 엔트리를 포함하는 NavigableMap을 반환한다. | 부분 맵 |
📌 TreeMap 사용
TreeMap과 HashMap의 차이점 부터 확인해 보자
TreeMap<Integer, String> map2 = new TreeMap<>();
map2.put(1, "Apple");
map2.put(38, "Banana");
map2.put(29, "Orange");
map2.put(52, "Grapes");
map2.put(14, "Strawberry");
System.out.println("TreeMap: " + map2);
Map<Integer, String> map3 = new HashMap<>();
map3.put(1, "Apple");
map3.put(38, "Banana");
map3.put(29, "Orange");
map3.put(52, "Grapes");
map3.put(14, "Strawberry");
System.out.println("HashMap: " + map3);
[결과]
TreeMap: {1=Apple, 14=Strawberry, 29=Orange, 38=Banana, 52=Grapes}
HashMap: {1=Apple, 52=Grapes, 38=Banana, 29=Orange, 14=Strawberry}
결과를 보면 TreeMap은 정렬이 되어서 나오고 HashMap은 정렬이 안되어서 나온다. 시간적으로는 괜찮은가? 확인해 보자
TimeCheck timer = new TimeCheck();
timer.start();
// 596221000
// Map<Integer, String> map = new HashMap<>();
// 1270982291
TreeMap<Integer, String> map = new TreeMap<>();
for(int i = 0; i < 10_000_000; i++) {
map.put(i, "String" + i);
}
timer.stop();
System.out.println(timer.getElapsedTimeInNano());
천만번의 put연산 결과 HashMap은 596,221,000 나노초가 걸렸고, TreeMap은 1,270,982,291 나노초가 걸렸다. 약 2배 정도 차이가 나는 것 같다. TreeMap은 내부 정렬을 계속 해서 시간이 더 걸리는것 같다.
Get연산도 시험해 봤는데 HashMap은 97,242,958 나노초, TreeMap은 629,957,458나노초가 걸렸다 Get연산 역시 TreeMap이 시간이 더 많이 걸리는것 같았다.
이유를 찾아보았다.
HashMap은 데이터를 해시 테이브레 저장하여 대부분의 경우 헤시 태이블에서 O(1) 시간 복잡도롤 데이터를 검색, 삽입, 삭제한다. 하지만 TreeMap의 경우 레드-블랙 트리로 데이터를 저장하여 삽입, 삭제, 검색 모두 O(log n)의 시간 복잡도를 가진다.
결론적으로 HashMap은 순서유지가 필요없을때 적합하고, TreeMap은 순서유지가 필요할때 적합하다.
📌 느낀점
요번에 처음으로 TreeMap에 대해 공부를 해봤는데 레드-블랙 트리라는 거대한 산을 또 마주쳐서 빨리 알아 보고 싶다. 레드-블랙 트리 까지 학습해야 TreeMap을 완벽히 이해할 수 있을 것 같다.