Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Структуры и алгоритмы обработки данных.doc
Скачиваний:
348
Добавлен:
12.03.2015
Размер:
1.81 Mб
Скачать

6.3. Удаление вершины из дерева поиска

Теперь рассмотрим удаление вершины из ДП. По сравнению с добавлением удаление реализуется более сложным алгоритмом, поскольку добавляемая вершина всегдаявляетсятерминальной, а удаляться можетЛЮБАЯ, в том числе и нетерминальная. При этом может возникать несколько различных ситуаций.

Рассмотрим фрагмент ДП с целыми ключами.

50

30

70

20

40

60

80

25

45

35

23

33

37

Ситуация 1. Удаляемая вершинане имеет ни одного потомка, т.е. является терминальной. Удаление реализуется очень легко обнулением соответствующего указателя у родителя. Например, для удаления вершины с ключом 23 достаточно установить 25.left=nil.

Ситуация 2. Удаляемая вершина имееттолько одного потомка. В этом случае удаляемая вершина вместе со своим потомком и родителем образуют фрагмент линейного списка. Удаление реализуется простым изменением указателя у родительского элемента. Например, для удаления вершины с ключом 20 достаточно установить 30.left= 20.right= 25

Ситуация 3. Пусть удаляемая вершина имеетдвух потомков. Этот случай наиболее сложен, поскольку нельзя просто в родительской вершине изменить соответствующее ссылочное поле на адрес одного из потомков удаляемой вершины. Это может нарушить структуру дерева поиска. Например, замена вершины 30 на одного из ее непосредственных потомков 20 или 40 сразу нарушает структуру дерева поиска.

Существует специальное правило для определения вершины, которая должна заменитьудаляемую. Это правило состоит из двух взаимоисключающих действий:

  • либо войти в левоеподдерево удаляемой вершины и в этом поддереве спустится как можно глубже, придерживаясь толькоправыхпотомков; это позволяет найти в дереве ближайшуюменьшуювершину (например, для вершины 30 это будет вершина 25)

  • либо войти в правоеподдерево удаляемой вершины и спустится в нем как можно глубже придерживаясь тольколевыхпотомков; это позволяет найти ближайшуюбОльшуювершину (например, для той же вершины 30 это будет вершина 33).

Перейдем к программной реализации процедуры удаления. Поскольку при удалении могут изменяться связи между внутренними вершинами дерева, удобно (но, конечно же, не обязательно) использовать рекурсивную реализацию. Основная процедура DeleteNode рекурсивно вызывает сама себя для поиска удаляемой вершины. После нахождения удаляемой вершины процедураDeleteNode определяет число ее потомков. Если потомков не более одного, выполняется само удаление. Если потомков два, то вызывается вспомогательная рекурсивная процедураChangerдля поиска вершины-заменителя.

Procedure DeleteNode ( var pCurrent : Tp);

VarpTemp : Tp;

Procedure Changer ( var p : Tp);

begin

{реализация рассматривается ниже}

end;

begin

ifpCurrent=nilthen“удаляемой вершины нет, ничего не делаем”

else

if x < pCcurrent^.inf then DeleteNode ( pCcurrent^.left)

else

if x > pCurrent^.inf then DeleteNode ( pCurrent^.right)

else {удаляемая вершина найдена}

begin

pTemp := pCurrent;

if pTemp^.right = nil then pCurrent := pTemp^.left

else

if pTemp^.left = nil then pCurrent := pTemp^.right

else{два потомка, ищем заменитель}

Changer ( pCurrent^.left); { а можно и pCurrent^.right }

Dispose ( pTemp);

end;

end;

Схема процедуры Changer:

begin

if p^.right <> nil then Changer ( p^.right)

else{правое поддерево пустое, заменитель найден, делаем обмен}

begin

pTemp^.inf:=p^.inf; {заменяем информац. часть удаляемой вершины}

pTemp:=p; {pTempтеперь определяет вершину-заменитель}

p:=p^.left; {выходной параметр адресует левого потомка заменителя}

end;

end;

Дополнительный комментарий к процедурам. Подпрограмма Changerв качестве входного значения получает адрес левого (или правого) потомка удаляемой вершины и рекурсивно находит вершину-заменитель. После этого информационная часть удаляемой вершины заменяется содержимым вершины-заменителя, т.е.фактического удаления вершины не происходит. Это позволяет сохранить неизменными обе связи этой вершины с ее потомками. Удаление реализуется относительновершины-заменителя, для чего ссылкаpTempпосле обмена устанавливается в адрес этой вершины. Кроме того, в самом конце процедурыChangerустанавливается новое значение выходного параметраp: оно равно адресу левого потомка вершины-заменителя. Это необходимо для правильного изменения адресной части вершины-родителя для вершины-заменителя. Само изменение происходит при отработке механизма возвратов из рекурсивных вызовов процедурыChanger. Когда все эти возвраты отработают, происходит возврат в основную процедуруDeleteNode, которая освобождает память, занимаемую вершиной-заменителем. Отметим, что приведенная выше реализация процедурыChangerориентирована на поиск в левом поддереве удаляемой вершины и требует симметричного изменения для поиска заменителя в правом поддереве.

Для окончательного уяснения данного алгоритма настоятельно рекомендуем провести ручную пошаговую отработку его для небольшого примера, как это было сделано для значительно более простого алгоритма построения идеально сбалансированного дерева.