TreeMap, SortedMap и NavigableMap в Java - Вопросы

Всего: 5 вопросов

1. 

Как устроен TreeMap в Java и как он сравнивает ключи?

TreeMap хранит пары в узлах красно-чёрного дерева — самобалансирующегося двоичного дерева поиска высотой порядка log n. Поэтому get(), put(), remove() и containsKey() выполняются за O(log n), а обход всегда идёт по возрастанию ключей.

Ключи сравниваются не через equals() и hashCode(), а через compareTo() (естественный порядок, ключ должен быть Comparable) или через Comparator, переданный в конструктор. Если сравнение вернуло 0, ключи считаются одинаковыми: put() заменит значение, а ключ останется прежним.

Отсюда два следствия: put(null, ...) при естественном порядке бросает NullPointerException, а ключ без Comparable и без компаратора — ClassCastException на первом put(). TreeMap реализует интерфейсы SortedMap и NavigableMap.

2. 

Чем интерфейс SortedMap отличается от NavigableMap?

SortedMap (Java 1.2) гарантирует обход по возрастанию ключей и добавляет firstKey(), lastKey(), comparator() и поддиапазоны headMap(to), subMap(from, to), tailMap(from): нижняя граница включается, верхняя — нет. Поддиапазоны — живые представления исходной карты; put() ключа вне диапазона бросает IllegalArgumentException: key out of range.

NavigableMap (Java 6) расширяет SortedMap методами навигации: lowerKey(), floorKey(), ceilingKey(), higherKey() и их Entry-версии, firstEntry()/lastEntry(), pollFirstEntry()/pollLastEntry(), descendingMap(), а также headMap(), tailMap(), subMap() с флагами inclusive для каждой границы. Реализации NavigableMap — TreeMap и потокобезопасный ConcurrentSkipListMap.

3. 

Чем отличаются методы lowerKey(), floorKey(), ceilingKey() и higherKey() в NavigableMap?

Все четыре ищут ближайший ключ и не требуют точного совпадения: lowerKey(k) — наибольший ключ строго меньше k (<), floorKey(k) — наибольший ключ меньше или равный k (≤), ceilingKey(k) — наименьший ключ больше или равный k (≥), higherKey(k) — наименьший ключ строго больше k (>). Если подходящего ключа нет, возвращается null.

Для карты с ключами 10, 20, 30, 40, 50: lowerKey(30) = 20, floorKey(30) = 30, ceilingKey(30) = 30, higherKey(30) = 40; для отсутствующего ключа 35 floorKey = 30, ceilingKey = 40; lowerKey(10) и higherKey(50) возвращают null. Методы lowerEntry(), floorEntry(), ceilingEntry(), higherEntry() возвращают пару целиком — неизменяемый снимок, у которого setValue() бросает UnsupportedOperationException.

4. 

Как с помощью NavigableMap выбрать значение по диапазону, например оценку по баллу?

Ключом карты делают нижнюю границу диапазона, а нужный диапазон находит floorEntry(value) — наибольший ключ, не превышающий значение. Это O(log n) вместо цепочки if-else:

NavigableMap<Integer, String> grades = new TreeMap<>();
grades.put(0, "неудовлетворительно");
grades.put(60, "удовлетворительно");
grades.put(75, "хорошо");
grades.put(90, "отлично");
grades.floorEntry(74).getValue(); // удовлетворительно

Если значение меньше самой нижней границы (например, -5), floorEntry() вернёт null, и getValue() бросит NullPointerException, поэтому шкала должна начинаться с минимально возможного значения или результат нужно проверять. Так же строят тарифы по весу, скидки по сумме и расписания: для интервала времени — subMap(from, true, to, true), для ближайшего события — ceilingEntry(now).

5. 

Когда выбирать TreeMap, а когда HashMap?

HashMap выбирают по умолчанию: get() и put() в среднем O(1), но порядок ключей не гарантирован; ключу нужны корректные equals() и hashCode(), один null-ключ разрешён.

TreeMap медленнее — O(log n) на операцию, — зато хранит ключи отсортированными по возрастанию или по Comparator, умеет искать ближайший ключ (floorKey(), ceilingEntry()), брать минимум и максимум и вырезать диапазоны (subMap()). Ключ должен быть Comparable или сравниваться компаратором; null-ключ при естественном порядке запрещён.

Частый приём — собрать данные в HashMap, а перед выводом один раз отсортировать: new TreeMap<>(hashMap). Обе карты не потокобезопасны: замена HashMap — ConcurrentHashMap, замена TreeMap — ConcurrentSkipListMap.

Страница 1 из 1