Деревья поиска. Организация: свойство упорядоченности и поиск за O(log N)
Деревья поиска. Организация: правило размещения ключей
Двоичные деревья часто употребляются для представления множеств данных, в которых необходимо осуществлять быстрый поиск элементов по ключу. Если дерево организовано таким образом, что для любой его вершины выполняется следующее жесткое правило: все ключи в ее левом поддереве строго меньше ее ключа, а все ключи в правом поддереве строго больше ее ключа, то такое дерево называется деревом поиска (Binary Search Tree, BST).
Главным преимуществом такой организации является существенное сокращение времени поиска по сравнению с линейными структурами (списками). На каждом шаге поиска, сравнивая искомый ключ с ключом текущего узла, алгоритм переходит либо в левое, либо в правое поддерево, автоматически отбрасывая половину оставшихся вариантов. В идеально сбалансированном дереве максимальное количество сравнений не превышает его высоты, которая пропорциональна log2(N), где N - количество элементов. Таким образом, время поиска значительно сокращается: O(log N) вместо O(N).
Поиск в дереве (алгоритм)
Процедура поиска в таком дереве чрезвычайно проста и не требует применения рекурсии (хотя рекурсивная реализация также возможна). Поиск начинается от корня и продвигается вниз по однозначно выбираемому пути, реализуясь одним циклом while.
struct node {
int key;
struct node* l;
struct node* r;
};
/* Итеративный поиск в дереве */
struct node* locate(int x, struct node* t) {
while (t != NULL && t->key != x) {
if (x < t->key) {
t = t->l; /* Идем в левое поддерево */
} else {
t = t->r; /* Идем в правое поддерево */
}
}
return t; /* Вернет NULL, если элемент не найден */
}
Визуализация организации дерева поиска
Рассмотрим пример правильно организованного двоичного дерева поиска. Обратите внимание, что для каждого узла выполняется главное правило: левые потомки меньше, правые - больше.
std::set и std::map в C++). В стандартной библиотеке Python нет прямой реализации двоичного дерева поиска. Ассоциативные массивы (словари dict) и множества (set) реализованы на основе хеш-таблиц, что обеспечивает константное время поиска O(1), но не сохраняет сортировку элементов. Если требуется именно упорядоченная древовидная структура, используют сторонние модули (такие как bintrees) или пишут свой класс дерева.
Коротко: главное
- Дерево поиска - это двоичное дерево, в котором ключи левого поддерева всегда меньше ключа узла, а ключи правого - больше.
- Такое свойство обеспечивает логарифмическое время поиска
O(log N)в сбалансированном случае, так как на каждом шаге отбрасывается половина дерева. - Поиск осуществляется простым итеративным спуском от корня, без необходимости использовать рекурсию.
Проверьте себя
За счет чего достигается алгоритмическая сложность O(log N) при поиске элемента в сбалансированном дереве поиска?