Left Right Left Right
Рис, 9.7. Операция удаления элемента X из бинарного словаря, прикоторой возникает проблема, связанная с тем. что нужно восстановить структуру дерева после удаления X
ЕСЛИ ОДНО ИЗ поддеревьев (Left ИЛИ Right) является пустым, решение упрощается: непустое поддерево должно быть присоединено к узлу А, А если оба поддерева непусты, то можно воспользоваться одной идеей, которая проиллюстрирована на рис, 9.8. Крайний левый узел поддерева Right (узел Y) переносится из его текущей позиции вверх для заполнения промежутка, образовавшегося в результате удаления узла X. После такого переноса дерево остается упорядоченным. Безусловно, та же идея допускает выполнение симметричной операции, предусматривающей перенос крайнего правого узла поддерева Left.
В соответствии с этими соображениями может быть составлена программа для операции удаления элемента из бинарного словаря, приведенная в листинге 9.5. Перенос крайнего левого узла правого поддерева осуществляется с помощью следующего отношения: delminl Tree, Y, Treel)
где У - наименьший (т.е. крайний левый) узел дерева Tree, a Treel - дерево Tree после удаления элемента Y.
Глава 9, Операции со структурами данных
RfgM |
Right |
flight |
rue. n.«. иперация заполнения промежутка, ооразовавшегося е результате удаления узла X
Листинг 9,5. Операция удаления из бинарного словаря
% del( Tree, X, NewTree):
% удаление элемента X ;'"-'. бинарного словаря Tree и получение словаря НеыТгее del( t( nil,X, Right), X, Right). dell t( Left, x, nil), X, Left).
del( t( Left, X, Right), X, t( Left, Y, Rightl)) :-
delmin( Right, Y, Rightl). del ( t( Left, Root, Right), X, t( Leftl, Root, Right)) Root, X) , del! Left, x, Leftl).
del ( t( Left, Root, Right), X, t( Left, Root, Rightl)) gt X, Root), del( Right, X, Rightl) ,
-
: -
% delminl Tree, ■, NewTree) :
удаление минимального элемента * и получение словаря NewTree
из бинарного словаря Tree
delraint t( nil,
R)
delmini t( Left, Root, Right), X, t( Leftl, Root, Right)) :-delmint Left, Y, Leftl).
Но для разработки операций добавления и удаления можно использовать другое изящное решение. Отношение add может быть определено недетерминированным способом, таким образом, чтобы вставка нового элемента выполнялась на любом уровне дерева, а не только на уровне листа. Ниже описаны правила выполнения такой операции вставки.
Чтобы ввести элемент X в бинарный словарь D, необходимо выполнить одно из следующих действий.
Ввести X в корень дерева D (так, чтобы X стал новым корнем).
Если корень D больше х, то вставить X в левое поддерево D, в противном случае вставить X в правое поддерево D.
Сложной частью этой операции является вставка элемента в корень дерева D. Сформулируем эту операцию как следующее отношение: addroot; D, X, D1)
где X — элемент, который должен быть вставлен а корень D, a D1 — результирующий словарь, корнем которого является X. Зависимости между X, D и D1 показаны на
Часть I. Язык Prolog
рис. 9.9. Остается найти ответ на вопрос о том. какими должны быть поддеревья Li и L2 на рис. 9.9 (или, при использовании другого варианта вставки, R1 и R2). Ответ на этот вопрос можно получить, рассмотрев следующие ограничения.
• L1 и L2 должны быть бинарными словарями.
• Множество узлов в и L2 равно множеству узлов в L.
• Все узлы в L1 меньше X и все узлы в I больше X.
._ итьХ /V в качестве кормр |
Х<У
Ycx
D1
Рис. 9.9. Примеры вставки X в качестве корнябинарного словаря
ЭТИ ограничения налагаются только одним отношением — addrcot- А именно, если X должен быть введен в дерево L в качестве корня, то поддеревьями результирующего дерева как раз и должны быть L1 и L2. В языке Prolog L1 и L2 должны соответствовать следующей цели: addrootf L, X, t( Lb X, L2
Те же ограничения распространяются на - и R2: addroot! Rr X, tl Rl, X, R2))
В листинге 9.6 приведена полная программа с определением операции "недетерминированной" вставки в бинарный словарь.
Листинг 9.6. Вставка в бинарный словарь на любом уровнедерева
i add( Tree, X, HewTree) : i вставка элемента X на любом уровне бинарного словаря Tree % и получение словаря КемТгее add[ Tree, X, HewTree) :- addroot; Tree, X, NewTree) . % Добавление элемента X в качестве нового корня |
addf t( L, Y, R) , Y,, t ( LI, i, R) ) gt( Y, x), add( L, X, LI) .
add{ t ( L, Y, RJ , X, 1 ( L, Y, Rl)
:;■ X, Y) ,
% вставка элемента Х в левое поддерево Вставка элемента X в правое поддерево
Глава 9. Операции со структурами данных
add( К, X, Rl) .
4 addrootf Tree, X, HewTree):
Ч вставка элемента Х в качестве корня в дерево Tree и получение дерева HewTree
addrootf nil,X, t[ nil,X, nil)). % Вставка в пустое дерево
addroot ( tt L, Y, " , X, t( . X, t( L2, Y, R) ) ) :-
gt( Y, X), addroott L, X, t( 1, X, L2>>.
addroott t( L, Y, R), X, t( t( L, Y, Rl), X, R2)) :-
gt( X, Y),
addroott R, X, t( Rl, X, R2) ) .
Важной отличительной особенностью этой процедуры вставки является то, что она не налагает ограничений на выбор уровня вставки. Поэтому такую процедуру add можно применить в обратном направлении, для удаления любого элемента из словаря. Например, следующий список целей формирует словарь : . содержащий элементы 3, 5, 1, 6, а затем удаляет элемент 5, что приводит к получению словаря DD
add( nil,3, Di), add ( Dl, 5, D2) , add f D2, 1, D3) , add( D3, 6, D) , add f DD, 5, D)