В set сложность вставки, удаления, поиска - логарифмическая
В структурах данных set (в C++ std::set, в Java TreeSet), операции вставки, удаления и поиска выполняются за логарифмическое время (O(log n)), но это справедливо не для всех реализаций, а только для тех, которые базируются на самобалансирующихся бинарных деревьях поиска (например, красно-черных деревьях).
📌 Что такое set?
set — это коллекция уникальных элементов, которая автоматически упорядочивает их при вставке (если используется дерево) или хэширует (если это unordered_set или HashSet).
📘 Основная реализация: std::set в C++
В C++, std::set реализован как красно-черное дерево, которое является разновидностью самобалансирующегося бинарного дерева поиска. Благодаря этому достигается гарантированная временная сложность:
Операция | Сложность |
---|---|
Вставка (insert) | O(log n) |
--- | --- |
Удаление (erase) | O(log n) |
--- | --- |
Поиск (find) | O(log n) |
--- | --- |
Минимум/максимум | O(log n) |
--- | --- |
Обход (итер.) | O(n) |
--- | --- |
Почему O(log n)?
-
При вставке, удалении или поиске элемент проходит путь от корня дерева до нужного узла.
-
Самобалансировка обеспечивает высоту дерева ≈ log₂(n).
-
Красно-черные деревья автоматически производят ротации и перекраски для удержания баланса.
📙 Пример: вставка
std::set<int> s;
s.insert(5); // логарифмическая вставка
s.insert(2);
s.insert(8);
-
После каждой вставки структура проверяет баланс.
-
Гарантируется, что глубина дерева остаётся логарифмической.
-
Дубликаты автоматически игнорируются.
📘 В Java: TreeSet
TreeSet в Java реализован на красно-черном дереве, как и std::set в C++. Поэтому:
Операция | Сложность |
---|---|
add(E e) | O(log n) |
--- | --- |
remove(Object o) | O(log n) |
--- | --- |
contains(Object o) | O(log n) |
--- | --- |
Пример:
TreeSet<Integer> set = new TreeSet<>();
set.add(10);
set.add(5);
set.add(20);
❗ Важное отличие: unordered_set и HashSet
Если использовать unordered_set в C++ или HashSet в Java:
-
Эти структуры используют хэш-таблицу.
-
Операции вставки, удаления, поиска имеют среднюю сложность O(1), но худшую — O(n).
-
Элементы не отсортированы.
-
При плохой хэш-функции возможны коллизии и снижение производительности.
Реализация | Упорядоченность | Сложность (средняя) | Сложность (худшая) |
---|---|---|---|
set / TreeSet | Да | O(log n) | O(log n) |
--- | --- | --- | --- |
unordered_set / HashSet | Нет | O(1) | O(n) |
--- | --- | --- | --- |
📚 Примеры сравнения
C++:
std::set<int> s; // O(log n)
std::unordered_set<int> us; // O(1) в среднем
Java:
Set<String> treeSet = new TreeSet<>(); // логарифмическая сложность
Set<String> hashSet = new HashSet<>(); // константная в среднем
🛠 Механизм вставки и поиска
Вставка:
-
Сравнение вставляемого элемента с корнем.
-
Рекурсивный спуск влево или вправо.
-
При достижении nullptr — добавление нового узла.
-
Выполнение балансирующих операций (ротации и перекраски).
Поиск:
-
Начало с корня.
-
Сравнение с текущим значением:
-
Меньше → идти влево.
-
Больше → идти вправо.
-
Равно → найден.
-
Каждый шаг отсекает половину дерева — O(log n).
🧠 Балансировка в красно-черном дереве
Красно-черное дерево поддерживает следующие инварианты:
-
Каждый узел — красный или черный.
-
Корень всегда черный.
-
Красный узел не может иметь красного потомка.
-
В любом поддереве одинаковое число черных узлов от корня до листа.
Благодаря этим правилам гарантируется, что высота дерева ≤ 2·log₂(n).
🔍 Использование set в алгоритмах
set часто используется:
-
Для поддержания множества уникальных значений.
-
Быстрого доступа к минимуму/максимуму.
-
Поиска ближайших значений (lower_bound, upper_bound).
-
Хранения отсортированных данных без дубликатов.
🧾 Реализация lower_bound / upper_bound
set.lower_bound(x) — найти \*\*первый элемент ≥ x\`.
-
В C++: auto it = s.lower_bound(x);
-
В Java: set.ceiling(x);
Реализуется бинарным поиском в дереве → O(log n)
📈 Итоги сложности в set
Операция | C++ std::set / Java TreeSet |
---|---|
Вставка (insert / add) | O(log n) |
--- | --- |
Удаление (erase / remove) | O(log n) |
--- | --- |
Поиск (find / contains) | O(log n) |
--- | --- |
Минимум/максимум (begin/last) | O(log n) |
--- | --- |
Обход в порядке возрастания | O(n) |
--- | --- |
Если используется set, базирующийся на сбалансированном дереве (красно-черном, AVL и т.д.), логарифмическая сложность гарантируется во всех случаях, в отличие от обычного бинарного дерева поиска или unordered_set.