
- •Содержание
- •Поиск в двоичном дереве…………………….……………………...5 Добавление и удаление элемента ………...…………………………..7
- •Введение
- •13.1. Что такое двоичное дерево поиска?
- •13.2. Поиск в двоичном дереве
- •Следующий и предыдущий элементы
- •13.3. Добавление и удаление элемента
- •13.4 Случайные двоичные деревья поиска
- •14 Красно-чёрные деревья
- •14.1. Свойства красно-чёрных деревьев
- •14.2. Вращения
13.3. Добавление и удаление элемента
Эти операции меняют дерево, сохраняя свойство упорядоченности. Как увидим, добавление сравнительно просто, а удаление чуть сложнее.
Добавление
Процедура tree-insert добавляет заданный элемент в подходящее меcто дерева Т (сохраняя свойство упорядоченности). Параметром процедуры является указатель z на новую вершину, в которую помещены значения key[z] (добавляемое значение ключа), left[z] =nil и right[z] = NIL. В ходе работы процедуры меняет дерево Т и (возможно) некоторые поля вершины 2, после чего новая вершина с данным значением ключа оказывается вставленной в подходя место дерева.
tree-!nsert(t\ z)
-
у <- nil
-
х <-root[Т]
-
while х<> nil
4 do у «— х
5 if key[z] < key[x]
-
then x «— left[x]
-
else x «— right[x]
-
p[z] <- у
-
if у = nil
-
then root[T] <- z
-
else if key[z] < key[y]
-
then left[y] <- z
-
else right[y] <— z
На рис. 13.3 показано, как работает процедура TREE-INSERT. Подобно процедурам tree-search и iterative-tree-search, она двигается вниз по дереву, начав с его корня. При этом в вершине у сохраняется указатель на родителе вершины х (цикл в строках 3-7). Сравнивая key[z] с key[x], процедура решает, куда идти — налево или направо. Процесс завершается, когда х становится равным nil. Этот nil стоит как раз там, куда надо поместить z, что и делается в строках 8-13. Как и остальные операции, добавление требует времени O(h) для дер высоты h
Рис. 13.3. Добавление элемента с ключом 13. Светло-серые вершины находятся на пути от корня до позиции нового элемента. Пунктир связывает новый элемент со старыми.
Удаление
Параметром процедуры удаления является указатель на удаляемую вершину. При удалении возможны три случая, показанные на рис. 13.4. Если у z нет детей, для удаления z достаточно поместить nil в соответствующее поле его родителя (вместо z). Если у z есть один ребёнок, можно «вырезать» z, соединив его родителя напрямую с его ребёнком. Если же детей двое, требуются некоторые приготовления: мы находим следующий (в смысле порядка на ключах) за z элемент у; у него нет левого ребёнка. Теперь можно скопировать ключ и дополнительные данные из вершины у в вершину z , а саму вершину у удалить описанным выше способом.
Примерно так и действует процедура TREE-DELETE (хотя рассматривает эти три случая в несколько другом порядке).
tree-delete(t, z}
1 if left[z]= NIL или right[z] = NIL
-
then у <- z
-
else у <- tree-successor(z)
4 if left[y] <> nil
5 then x <- left[y]
6 else x <- right[y]
7 if x <> nil
8 then p[x] <- p[y]
9 if p[y] = nil
-
then root[T] <- x
-
else if у = left[p[y]]
-
then left[p[y]] <-x
-
else right[p[y]] <- x
14 if у <> z
15 then key[z] <- key[y]
16 t> Копируем дополнительные данные, связанные с у.
17 return у
Рис. 13.4. Удаление вершины z из двоичного дерева поиска (а). Если вершина z не имеет
детей, её можно удалить без проблем (б). Если вершина r имеет одного ребёнка, помещаем её на место вершины z (в). Если у вершины z двое детей, мы сводим дело к предыдущему случаю, удаляя вместо неё вершину у с непосредственно следующим значением ключа (у этой вершины ребёнок один) и помещая ключ key[y] (и связанные с ним дополнительные данные) на место вершины z.
В строках 1-3 определяется вершина у, которую мы потом вырежем из дерева. Это либо сама вершина z (если у r не более одного ребёнка), либо следующий за z элемент (если у z двое детей). Затем в строках 4-6 переменная х становится указателем на существующего ребёнка вершины у, или равной NIL, если у у нет детей. Вершина у вырезается из дерева в строках 7-13 (меняются указатели в вершинах р[у] и х). При этом отдельно рассматриваются граничные случаи когда х = NIL или когда у является корнем дерева. Наконец, в строках 14-16, если вырезанная вершина у отлична от z, ключ (и дополнительные данные) вершины у перемещаются в z (ведь нам надо было удалить z, а не у). Haконец, процедура возвращает указатель у (это позволит вызывающей процедуре впоследствии освободить память, занятую вершиной у). Время выполнения есть O(h) на дереве высоты h.
Итак, мы доказали следующую теорему.
Теорема 13.2. Операции insert и delete могут быть выполнены за время O(h), где h — высота дерева.