Удаление элемента из RB дерева

Осуществляется посредством процедуры rb_delete (см. таблицу 6).

Именно здесь приобретает силу замена nil на nul, которая позволяет обходить некоторые граничные случаи. Теперь «nil»-лист логически – вершина, у которой действителен указатель на предка p и цвет c.

Начинаем с обычного удаления вершины из дерева. После чего возникает два случая:

удаление красной вершины не противоречит ни одному условию RB; удаляемая вершина черная – для ее родителя черные высоты детей будут различны[4]. Требуется балансировка.

Второй случай приводит нас к процедуре rb_delete_fixup (Таблица 5). Основной цикл продолжает работу до тех пор, пока вершина, на которую указывает x, не станет черной или, корнем дерева. Однотипные случаи (симметричные) разделяются строчкой (1) кода.

После удаления в ветви дерева, на родителя которой указывает
x, не хватает единицы черноты – исправляем посредством ее брата или родителя. Для подробного разбора кода мы приводим рис. 3, который наглядно иллюстрирует динамику изменения структуры дерева после преобразований

Приложение

Индексация

Код

№ таблицы и комментарий

Const

red=true;

black=false;

Type

t_el=integer;

t_rb=^t_rb_rec;

t_rb_rec=record

el:t_el;

l,r,p:t_rb;

c:boolean;

end;

Таблица 1

function rb_new(el:t_el; nul:pointer; c:boolean):t_rb;

var

t:t_rb;

begin

new(t);

t^.l:=nul;

t^.r:=nul;

t^.el:=el;

t^.p:=nul;

t^.c:=c;

rb_new:=t;

end;

procedure tree_ins(var t:t_rb; z:t_rb);

var

y,x:t_rb;

begin

y:=nul;

x:=t;

while x<>nul do begin

y:=x;

if z^.el<x^.el then
x:=x^.l

else x:=x^.r;

end;

z^.p:=y;

if y=nul then t:=z

else begin

if z^.el<y^.el then
y^.l:=z

else y^.r:=z;

end;

end;

Таблица 2

t – корень дерева

z – указатель на вставляемый элемент

Здесь формируется вызовом функции rb_new.

nul:=rb_new(0,nil,black), а

<любой элемент дерева>:=rb_new(el,nul,red), что избавляет нас от написания дополнительного кода для инициализации самого nul.

1

2

3

4

5

5.1

5.2

6

7

1

2

3

4

5

5.1

5.2

6

7

procedure rb_left_rotate(var t:t_rb; x:t_rb);

var

y:t_rb;

begin

y:=x^.r;

x^.r:=y^.l;

if
y^.l<>nil then y^.l^.p:=x;

y^.p:=x^.p;

if
x^.p=nil then t:=y

else begin

if x=x^.p^.l then
x^.p^.l:=y

else x^.p^.r:=y;

end;

y^.l:=x;

x^.p:=y;

end;

procedure rb_right_rotate(var t:t_rb; x:t_rb);

var

y:t_rb;

begin

y:=x^.l;

x^.l:=y^.r;

if y^.r<>nil then y^.r^.p:=x;

y^.p:=x^.p;

if x^.p=nil then t:=y

else begin

if x=x^.p^.r then x^.p^.r:=y

else x^.p^.l:=y;

end;

y^.r:=x;

x^.p:=y;

end;

Таблица 3

Рис. 4

Рис. 5

1

2

C1-C1’

С2-C2’

С3

С3-C3’

Procedure rb_ins(var
t:t_rb; x:t_rb);

var

y:t_rb;

b:boolean;

begin

tree_ins(t,x);

x^.c:=red;

while (x<>t)and(x^.p^.c=red) do begin

b:=(x^.p=x^.p^.p^.l);

if b then
y:=x^.p^.p^.r

else y:=x^.p^.p^.l;

if (y<>nul)and(y^.c=red) then begin

x^.p^.c:=black;

y^.c:=black;

x^.p^.p^.c:=red;

x:=x^.p^.p;

end else begin

if b then begin

if x=x^.p^.r then begin

x:=x^.p;

rb_left_rotate(t,x)

end;

end else begin

if x=x^.p^.l then begin

x:=x^.p;

rb_right_rotate(t,x);

end;

end;

x^.p^.c:=black;

x^.p^.p^.c:=red;

if b then rb_right_rotate(t,x^.p^.p)

else rb_left_rotate(t,x^.p^.p);

end;

end;

t^.c:=black;

end;

Таблица 4

(1)

С1

С2

С3

С4

С1’

С2’

С3’

С4’

procedure rb_delete_fixup (var t:trb; x:trb);

var

w:t_rb;

begin

while (x<>t)and(x^.c=black) do begin

if x=x^.p^.l then begin

w:=x^.p^.r;

if (w^.c=red) then begin

w^.c:=black;

x^.p^.c:=red;

rb_left_rotate(t,x^.p);

w:=x^.p^.r;

end;

if (w^.l^.c=black)and(w^.r^.c=black) then begin

w^.c:=red;

x:=x^.p;

end else begin

if (w^.r^.c=black) then begin

w^.l^.c:=black;

w^.c:=red;

rb_right_rotate(t,w);

w:=x^.p^.r;

end;

w^.c:=x^.p^.c;

x^.p^.c:=black;

w^.r^.c:=black;

rb_left_rotate(t,x^.p);

x:=t;

end;

end else begin

w:=x^.p^.l;

if (w^.c=red) then begin

w^.c:=black;

x^.p^.c:=red;

rb_right_rotate(t,x^.p);

w:=x^.p^.l;

end;

if (w^.l^.c=black)and(w^.r^.c=black) then begin

w^.c:=red;

x:=x^.p;

end else begin

if (w^.l^.c=black) then begin

w^.r^.c:=black;

w^.c:=red;

rb_left_rotate(t,w);

w:=x^.p^.l;

end;

w^.c:=x^.p^.c;

x^.p^.c:=black;

w^.l^.c:=black;

rb_right_rotate(t,x^.p);

x:=t;

end;

end;

end;

x^.c:=black;

end;

Таблица 5

function tree_next(x:t_rb):t_rb;

var

y:t_rb;

begin

if x^.r<>nul then
begin

x:=x^.r;

while x^.l<>nul do
x:=x^.l;

tree_next:=x;

end else begin

y:=x^.p;

while (y<>nul)and(x=y^.r) do begin

x:=y;

y:=x^.p;

end;

tree_next:=y;

end;

end;

function rb_delete(var t:t_rb; z:t_rb):t_rb;

var

y,x:t_rb;

begin

if z<>nul then begin

if (z^.l=nul)or(z^.r=nul) then y:=z

else y:=tree_next(z);

if y^.l<>nul then
x:=y^.l

else x:=y^.r;

x^.p:=y^.p;

if y^.p=nul then t:=x

else begin

if y=y^.p^.l then y^.p^.l:=x

else y^.p^.r:=x;

end;

if y<>z then
z^.el:=y^.el;

if y^.c=black then
rb_fix(t,x);

rb_delete:=y;

end else rb_delete:=z;

end;

Таблица 6

Похожие записи

Добавить комментарий