← Назад ко всем вопросам

Когда сложность поиска в бинарном дереве не логарифмическая

1️⃣ Как кратко ответить

Сложность поиска в бинарном дереве не является логарифмической, когда дерево не сбалансировано. В худшем случае, если дерево вырождается в линейную структуру, сложность поиска становится O(n), где n — количество узлов в дереве.

2️⃣ Подробное объяснение темы

Бинарное дерево поиска (BST) — это структура данных, в которой каждый узел имеет не более двух потомков. Для каждого узла все значения в левом поддереве меньше значения узла, а все значения в правом поддереве больше. Это свойство позволяет эффективно выполнять операции поиска, вставки и удаления.

Логарифмическая сложность

В идеальном случае, когда бинарное дерево сбалансировано, высота дерева составляет O(log n), где n — количество узлов. Это происходит потому, что на каждом уровне дерева количество узлов удваивается, и высота дерева растет логарифмически относительно количества узлов. В таком случае операции поиска, вставки и удаления выполняются за O(log n).

Когда сложность не логарифмическая

Однако, если дерево не сбалансировано, оно может выродиться в линейную структуру, напоминающую связный список. Это происходит, когда элементы добавляются в дерево в отсортированном порядке (например, по возрастанию или убыванию). В этом случае каждый узел имеет только одного потомка, и высота дерева становится равной количеству узлов, то есть O(n). Соответственно, сложность поиска, вставки и удаления также становится O(n).

Пример

Рассмотрим пример, когда элементы добавляются в бинарное дерево в отсортированном порядке:

#include <iostream>
​
// Структура узла бинарного дерева
struct Node {
    int data; // Значение узла
    Node* left; // Указатель на левое поддерево
    Node* right; // Указатель на правое поддерево
    Node(int value) : data(value), left(nullptr), right(nullptr) {} // Конструктор узла
};
​
// Функция для вставки нового узла в бинарное дерево
Node* insert(Node* root, int value) {
    if (root == nullptr) {
        return new Node(value); // Создаем новый узел, если дерево пустое
    }
    if (value < root->data) {
        root->left = insert(root->left, value); // Вставляем в левое поддерево, если значение меньше
    } else {
        root->right = insert(root->right, value); // Вставляем в правое поддерево, если значение больше или равно
    }
    return root;
}
​
// Функция для поиска значения в бинарном дереве
bool search(Node* root, int value) {
    if (root == nullptr) {
        return false; // Если узел пустой, значение не найдено
    }
    if (root->data == value) {
        return true; // Значение найдено
    }
    if (value < root->data) {
        return search(root->left, value); // Ищем в левом поддереве
    } else {
        return search(root->right, value); // Ищем в правом поддереве
    }
}
​
int main() {
    Node* root = nullptr;
    // Вставляем элементы в отсортированном порядке
    root = insert(root, 1);
    root = insert(root, 2);
    root = insert(root, 3);
    root = insert(root, 4);
    root = insert(root, 5);
​
    // Поиск элемента
    std::cout << "Поиск 3: " << (search(root, 3) ? "Найден" : "Не найден") << std::endl;
    std::cout << "Поиск 6: " << (search(root, 6) ? "Найден" : "Не найден") << std::endl;
​
    return 0;
}

В этом примере элементы добавляются в дерево в порядке возрастания, что приводит к вырождению дерева в линейную структуру. Поиск элемента в таком дереве имеет сложность O(n), так как в худшем случае необходимо пройти через все узлы.

Заключение

Чтобы избежать вырождения бинарного дерева в линейную структуру и сохранить логарифмическую сложность операций, используют самобалансирующиеся деревья, такие как AVL-деревья или красно-черные деревья. Эти структуры данных автоматически поддерживают балансировку, обеспечивая высоту дерева O(log n) и, соответственно, логарифмическую сложность операций.

Тема: Алгоритмы / Структуры данных (общее)
Стадия: Tech

🔒 Подпишись на бусти автора и стань Алигатором, чтобы получить полный доступ к функционалу сайта и отслеживать свой прогресс!

Твои заметки