Часть V : avl – Деревья
Бинарное дерево является сбалансированным, если для любого узла дерева высоты его левого и правого поддеревьев отличаются не более чем на 1
-1, левое поддерево выше на 1
balance = 0, высота поддеревьев одинаковая
+1, правое поддерево выше на 1
Node (balance,key,left,right,parent) or {balance -> int hleft; int hright;}
Вставить новый элемент как в двоичное дерево поиска
Скорректировать свойство сбалансированности узлов дерева
При необходимости скорректировать само AVL-дерево
Коррекция узлов
x – новый узел дерева
q = x
p = q->parent – родительский узел
while p ≠ EList и p->balance = 0 {
if q в левом поддереве p
p->balance = -1
else
p->balance = +1
q = p
p = q->parent
}
p – узел дерева, у которого p->balance ≠ 0, или EList
if p = EList
успех
if x в левом поддереве p и p->balance = +1 или x в правом поддереве p и p->balance = -1 {
p->balance = 0
успех
}
Удалить элемент так же, как в двоичном дереве поиска (с учетом внешних листьев – EList)
Скорректировать свойство сбалансированности узлов дерева
При необходимости скорректировать само AVL-дерево
Удалить узел из бинарного дерева поиска
x – дочерний узел удаленного элемента
p = x->parent
while p ≠ EList {
коррекция узла дерева p:
if x в левом поддереве p
p->hleft = p->hleft – 1
else
p->hright = p->hright – 1
dh = | p->hleft – p->hright |
if dh > 1{
коррекция дерева
успех
}
else
if dh = 1
успех
else
x = p
p = x->parent
} -- цикл while
p – узел AVL-дерева, для которого нарушены требования сбалансированности
insert()
{
p =root
if(p==NULL) p = new;
else if ( key<p->key)
{
insert(p->left);
if((p->left->h) – (p->right->h) == 2){
if(key < p->left->key){rotate_r(p)}
else {rotate_r(p->left); rotate_l(p);
}
}
else
{
insert(p->right);
if((p->right->h) – (p->left->h) == 2){
if(key < p->left->key){rotate_r(p)}
else {rotate_r(p->left); rotate_l(p);
}
}
}
Часть VI : b – Деревья
В-дерево степени t:
Каждый узел, кроме корня и листьев, имеет минимум t, максимум 2t дочерних узлов
Каждый узел, кроме корня, содержит минимум t – 1, максимум 2t – 1 ключей; узел заполнен, если он имеет ровно 2t – 1 ключей
Корень имеет минимум 1 ключ и два дочерних узла
Все листья расположены на одной и той же глубине, которая равна высоте дерева h
Поиск в В-дереве
Если ключ содержится в корне, он найден. Иначе определяем интервал и идём к соответствующему сыну. Повторяем, пока не дошли до листа.
Вставка в В-дерево
Будем называть деревом потомков некоего узла поддерево, состоящее из этого узла и его потомков.
Вначале
определим функцию, которая добавляет
ключ K к дереву потомков узла x. После
выполнения функции во всех пройденных
узлах, кроме, может быть, самого узла x,
будет меньше
,
но не меньше
,
ключей.
Если х - не лист,
Определяем интервал, где должен находиться K. Пусть y - соответствующий сын.
Рекурсивно добавляем K к дереву потомков y.
Если узел y полон, то есть содержит ключей, расщепляем его на два. Узел
получает
первые
из
ключей y и первые
его
потомков, а узел
-
последние
из
ключей y и последние
его
потомков. Медианный из ключей узла y
попадает в узел х, а указатель на y в
узле x заменяется указателями на
узлы
и
.
Если x - лист, просто добавляем туда ключ K.
Теперь определим добавление ключа K ко всему дереву. Буквой R обозначается корневой узел.
Добавим K к дереву потомков R.
Если R содержит теперь ключей, расщепляем его на два. Узел
получает
первые
из
ключей R и первые
его
потомков, а узел
-
последние
из
ключей R и последние
его
потомков. Медианный из ключей узла R
попадает вo вновь созданный узел, который
становится корневым. Узлы
и
становятся
его потомками.
Удаление элемента
Если
корень одновременно является листом,
то есть в дереве всего один узел, мы
просто удаляем ключ из этого узла. В
противном случае сначала находим узел,
содержащий ключ, запоминая путь к нему.
Пусть этот узел -
.
Если
-
лист, удаляем оттуда ключ. Если в
узле
осталось
не меньше
ключей,
мы на этом останавливаемся. Иначе мы
смотрим на количество ключей в следующем,
а потом в предыдущем узле. Если следующий
узел есть, и в нём не менее
ключей,
мы добавляем в
ключ-разделитель
между ним и следующим узлом, а на его
место ставим первый ключ следующего
узла, после чего останавливаемся. Если
это не так, но есть предыдущий узел, и в
нём не менее
ключей,
мы добавляем в
ключ-разделитель
между ним и предыдущим узлом, а на его
место ставим последний ключ предыдущего
узла, после чего останавливаемся.
Наконец, если и с предыдущим ключом не
получилось, мы объединяем узел
со
следующим или предыдущим узлом, и в
объединённый узел перемещаем ключ,
разделяющий два узла. При этом в
родительском узле может остаться
только
ключей.
Тогда, если это не корень, мы выполняем
аналогичную процедуру с ним. Если мы в
результате дошли до корня, и в нём
осталось от 1 до
ключей,
делать ничего не надо, потому что корень
может иметь и меньше
ключей.
Если же в корне не осталось ни одного
ключа, исключаем корневой узел, а его
единственный потомок делаем новым
корнем дерева.
Если
-
не лист, а K - его
-й
ключ, удаляем самый правый ключ из
поддерева потомков
-го
сына
,
или, наоборот, самый левый ключ из
поддерева потомков
-го
сына
.
После этого заменяем ключ K удалённым
ключом. Удаление ключа происходит так,
как описано в предыдущем абзаце.
