Определение
Деревья поиска - деревья, хранящие в вершинах некоторые значения, называемые ключами, а также умело манипулирующие ими. Все операции обычно выполняются за высоту дерева, а для удобно перемещения по нему, дерево обычно хранит значения в определенном порядке, зачастую отсортированы по ключам.
Что зачастую умеют:
- add x - O(h)
- remove x - O(h)
- find x - O(h)
- lower_bound x - O(h)
- merge - O(h)
- split - O(h)
Двоичные деревья поиска
Определение
Двоичное бинарное дерево - бинарное дерево, в каждой вершине которого записано значение, называем ключом, причем, если в вершине лежит x
, то в поддереве ее левого сына лежат только вершины, меньшие x
, а в поддереве правого сына - большие x
.
Основные операции в ДДП
Поиск элемента
Алгоритм:
- Встаем в корень
- Сравниваем элемент, который хотим вставить с текущим, идем вправо или влево в зависимости от результата сравнения.
- Если мы пришли в элемент с нужным ключом, то нашли его в дереве, если нет, то должны когда-то из дерева выйти, это значит, что ключа в нем нет. Работает все это, очевидно, за высоту дерева.
Код
bool exists(node *root, int key) {
if (root == nullptr) {
return false;
}
if (root->key == key) {
return true;
}
if (root->key > key) {
return exists(root->l, key);
}
return exists(root->r, key);
}
Добавление элемента
Алгоритм:
- Встаем в корень
- Сравниваем элемент, который хотим вставить с текущим, идем вправо или влево в зависимости от результата сравнения.
- Если пришли в элемент, ключ которого равен тому, что мы пытаемся добавить, то ничего делать не надо, если же мы смогли выйти из дерева, то создаем новую вершину и привязываем ее туда, откуда мы вышли, правила дерева не нарушатся, так как мы все время шли в нужную сторону.
Код
node *insert(node *root, int key) {
if (root == nullptr) {
node *nw = new node();
nw->h = 1;
nw->key = key;
return nw;
}
if (root->key == key) {
return root;
}
if (root->key > key) {
root->l = insert(root->l, key);
} else {
root->r = insert(root->r, key);
}
root = balance(root);
return root;
}
Удаление элемента
Сначала нужно найти элемент, который мы хотим удалить, для Если у удаляемой вершины нет сыновей, или сын один, то мы можем просто его выкинуть и перепривязать потомка, ничего не сломается. Если сыновей два, то мы ищем самого большого потомка в правом поддереве, у него всего один потомок, мы свапаем его с нужной вершиной, дерево при этом не ломается, ну и теперь удалить нужную вершину не представляет труда.
AVL -дерево
Создатели:
- Адельсон-Вельсский
- Ландис
Принцип работы
Заведем отображение h(T), равный высоте дерева T. В дереве AVL будем поддерживать: Где L и R соответственно левое и правое поддерево любой вершины исходного дерева v. Лемма. В дереве высоты h хотя вершины, где - ое число Фибоначчи. Доказательство: Легко просто вывести формулу: Из этого можно понять, что высота дерева растет логарифмично, так как и числа Фибоначчи растут логарифмично.