Исключение элемента из дерева
Поможем в ✍️ написании учебной работы
Поможем с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой

Удаление узла дерева не должно нарушать упорядоченность дерева. При удалении возможны 3 расположения узлов:

1) найденный узел является листом - он просто удаляется;

2) найденный узел имеет только сына - в этом случае сын перемещается на место удаленного отца;

3) у удаляемого отца два сына - в этом случае основная трудность состоит в удалении отца, поскольку в удаляемую вершину входит одна стрелка, а выходит две. В этом случае нужно найти подходящее звено поддерева, которое должно занять место удаляемого без нарушения упорядоченности дерева. Данным звеном может быть либо предшественник удаляемого узла, либо его приемник.

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

Приемник - это самый левый элемент правого поддерева (для достижения этого элемента необходимо перейти в следующий узел по правой ветви, а затем двигаться только по левой ветви этого узла до тех пор, пока очередная ссылка не будет равна nil).

Очевидно, что такие подходящие звенья могут иметь не более одной ветви.

На изображенном ниже рисунке проиллюстрированы возможные удаляемые из дерева узлы при трех возможных вариантах (лист (ключ 1), один сын (ключ 6), два сына (ключ 12)).

Предшественником удаляемого узла (12) является самый правый узел левого поддерева (11). Преемником узла (12) - самый левый узел правого поддерева (13).

 

Нижеприведенный в псевдокоде алгоритм разработан для поиска по дереву с удалением для всех трех возможных случаев нахождения узлов, причем в случае наличия у удаляемого узла двух сыновей его место занимает преемник (на рисунке узел 13 занимает место удаляемого узла 12).

Введем указатели:

p - рабочий указатель;

q - отстает от р на один шаг;

v - указывает на преемника удаляемого узла;

t - отстает от v на один шаг;

s - на один шаг впереди v (указывает на левого сына или пустое место).

   В результате поиска преемника на узел 13 должен указывать указатель v, а указатель s - на пустое место (как показано на рисунке).

 q = nil

p = tree

while (p <> nil) and (k(p) <> key) do

q = p

if key < k(p) then

               p = left(p)

                    else

               p = right(p)

endif

endwhile

if p = nil then ‘Ключ не найден

                 return

endif

if left(p) = nil then v = right(p)

                  else if right(p) = nil

                          then v = left(p)

                          else

У nod(p) - два сына

Введем два указателя (t отстает от v на 1 шаг, s - опережает)’

              t = p

              v = right(p)

              s = left(v)

while s <> nil do

      t = v

      v = s

      s = left(v)

           endwhile

           if t <> p then

  ‘v не является сыном p’

      left(t) = right(v)

      right(v) = right(p)

           endif

      left(v) = left(p)

endif

endif

if q = nil then ‘p - корень

                 tree = v

         else if p = left(q)

                   then left(q) = v

                     else right(q) = v

                 endif

endif

freenode ( p )

return

 

Контрольные вопросы по теории (поиск по дереву с включением)

 

Включение элемента в дерево

1. В каком дереве при бинарном поиске нужно перебрать в среднем N/2 элементов?

 - A ;

 - B ;

 - C .

2. Сколько нужно перебрать элементов в сбалансированном дереве при бинарном поиске?

· A - N/2;;

· B - Ln(N);;

· C- Log2(N);;

· D - eN .

.

3. Выберете вариант дерева, полученного после вставки узла - 1.

 - A ;

 - B ;

 - C .

4. К какому элементу присоединить элемент 40 для вставки его в данное дерево?

 - к 30-му;

 - к 15-му;

 - к –15-му;

 - к 5-му.

5. Какой вид примет дерево после вставки элемента с ключом 58?

 - A;

 - B;

 - C.

В. Исключение элемента из дерева

1. Выберете вариант дерева, полученного после удаления узла – 3.

 - A ;

 - B ;

 - C .

2. Какой вариант дерева получится после удаления элемента – 1, а затем – 8?

 - A ;

 - B ;

 - C .

3. Выберете вариант дерева, полученного после удаления узла с индексом 0.

 - A ;

 - B ;

 - C .

4. Какие из следующих пар чисел могут стать корнями дерева после удаления элемента 10 в соответствии с двумя способами удаления узла, имеющего двух сыновей?

 - 0 или 15;

 - 0 или 20;

 - 5 или 30;

 - 5 или 15.

5. Какой вид примет дерево после удаления элемента с ключом 58?

 - A ;

 - B ;

 - C .

Примеры алгоритмов конкретных задач (поиск по дереву с включением, исключением)

 

Рассмотрим теперь, как реализуются алгоритмы поиска по дереву с включением и исключением на языке программирования С++.

Для простоты будем рассматривать бинарное упорядоченной дерево, в полях элементов которого ключи – вещественные числа, а поля записей отсутствуют. Описание самого элемента, функции создания и обхода подобного дерева подробно описаны в лабораторной работе № 3, поэтому здесь мы на них останавливаться не будем. Функция поиска со вставкой при уже созданном дереве будет иметь следующий вид:

 

void Vstavka ( double key ) //функция, вставляющая элемент в дерево

{Q=NULL;

P=tree;

while(P)

{ Q = P ;

if ( key == P -> k )

{ cout <<"\ n В дереве уже есть такой элемент, он найден, вставлять не надо\ n ";

return ;

/*если такой элемент в дереве уже есть, то функция завершает свою работу*/

}

if(key<P->k) P=P->left;

else P=P->right;

 };

V=new element;

V->k=key;

V->left=V->right=NULL;

if(key<Q->k) Q->left=V;

else Q -> right = V ;

}

 

Функция поиска с удалением при уже созданном дереве будет иметь следующий вид:

 

void Poisk_Udalenie (double key) //функция поиска с удалением

{Q=NULL;

P=tree;

{ while(P&&P->k!=key)

{ Q=P;

if(key<P->k) P=P->left;

else P=P->right;

};

if(!P) { cout<<" Ключ не найден !"; return;};

if(P->left==NULL) V=P->right;

   else

           {if(P->right==NULL) V=P->left;

                   else

                    { T=P;

                   V=P->right;

                   S=V->left;

                    while(S)

                   { T=V;

                   V=S;

                   S=V->left;

                   };

                   if(T!=P) { T->left=V->right;

                   V->right=P->right;

                    }

                   V->left=P->left;

           }

}

if(Q==NULL) tree=V;      

   else

   if(P==Q->left) Q->left=V;

           else Q->right=V;

delete P;

}

}

Теперь пример программы, в которой создается вышеописанное дерево и осуществляется вставка элемента в него

 

/*Поиск по дереву со вставкой, обходы слева направо */

#include<iostream.h>

#include<conio.h>

struct element

{ double k;

element* left;

element* right;

};

element *tree=NULL,*P,*Q, *V;

void maketree(double a)

{ if(!tree)

{ tree=new element;

  tree->k=a;

tree->right=tree->left=NULL;

P=tree;

Q=NULL;

return;

};

 P=Q=tree;

 while (P!=NULL)

 { Q=P;

if(a<P->k) P=P->left; else P=P->right;

 };

if(a<Q->k) { Q->left=new element;

     Q->left->k=a;

     Q->left->left=Q->left->right=NULL;

   }

else { Q->right=new element;

     Q->right->k=a;

     Q->right->left=Q->right->right=NULL;

   };

}

void Vstavka(double key) //функция вставляющая элемент в дерево

{

P=tree;

Q=NULL;

while(P)

{ Q=P;

if(key==P->k)

{cout<<"\n В дереве уже есть такой элемент, он найден, вставлять не надо\n";

return;

/*если такой элемент в дереве уже есть, то функция завершает свою работу*/

}

if(key<P->k) P=P->left;

else P=P->right;

 };

V=new element;

V->k=key;

V->left=V->right=NULL;

if(key<Q->k) Q->left=V;

else Q->right=V;

}

void printree(element* tree)

{ if(tree)

 { printree(tree->left);

cout<<tree->k<<" ";

printree(tree->right);

 };

}

void main()

{ clrscr();

double a,key;

cout<<"\n Введите элементы дерева, 0 - конец ввода: \n";

cin>>a;

while(a)

{ maketree(a);

cin>>a;

};

printree(tree);

cout<<endl<<" Введите ключ вставляемого элемента : ";

cin>>key;

Vstavka(key);

printree(tree);

getch ();

}

/*-------------------------------------------------------------------------------------- */

 

Следующий пример – программа создания бинарного дерева с последующим поиском и удалением найденного элемента  

 

/*Поиск по дереву со вставкой, обходы слева направо */

#include<iostream.h>

#include<conio.h>

struct element

{ double k;

element* left;

element* right;

};

element *tree=NULL,*P,*Q, *V, *T, *S;

void maketree(double a) //функция, создающая (добавляющая) элемент в) дерево

{ if(!tree)

{ tree=new element;

tree->k=a;

tree->right=tree->left=NULL;

P=tree;

Q=NULL;

return;

};

 P=Q=tree;

 while (P!=NULL)

 { Q=P;

if(a<P->k) P=P->left; else P=P->right;

 };

if(a<Q->k) { Q->left=new element;

     Q->left->k=a;

     Q->left->left=Q->left->right=NULL;

   }

else      { Q->right=new element;

     Q->right->k=a;

     Q->right->left=Q->right->right=NULL;

   };

}

void Poisk_Udalenie (double key) // функция поиска с удалением

{

Q=NULL;

P=tree;

{ while(P&&P->k!=key)

{ Q=P;

if(key<P->k) P=P->left;

else P=P->right;

};

if(!P) { cout<<" Ключ не найден !"; return;};

if(P->left==NULL) V=P->right;

   else

           {if(P->right==NULL) V=P->left;

                   else

                    { T=P;

                   V=P->right;

                   S=V->left;

                    while(S)

                   { T=V;

                   V=S;

                   S=V->left;

                   };

                   if(T!=P) { T->left=V->right;

                   V->right=P->right;

                    }

                   V->left=P->left;

           }

}

if(Q==NULL) tree=V;      

   else

   if(P==Q->left) Q->left=V;

           else Q->right=V;

delete P;

}

}

void printree ( element * tree )//функция вывода дерева на экран

{ if(tree)

 { printree(tree->left);

cout<<tree->k<<" ";

printree(tree->right);

};}

void main()

{ clrscr();

double a,key;

cout <<"\ n Введите элементы дерева, 0 - конец ввода: \ n ";

cin>>a;

while(a)

{ maketree(a);

cin>>a;

};

printree(tree);//печать дерева до удаления из него элемента

Q=NULL;

P=tree;

cout<<endl<<"Введите ключ удаляемого элемента: ";

cin>>key;

Poisk_Udalenie(key);

printree(tree);

getch();

}

/*-------------------------------------------------------------------------------------- */

 

Задания

Используя генератор случайных чисел сформировать бинарное дерево, состоящее из 15 элементов (предусмотреть ручной ввод элементов). Причем числа должны лежать в диапазоне от -99 до 99. Произвести поиск со вставкой и удалением элементов в соответствии со следующими вариантами заданий:

1. Числа кратные N.

2. Нечетные числа.

3. Числа > N.

4. Числа < N.

5. Числа по выбору.

6. Простые числа.

7. Составные числа.

8. Числа в интервале от X до Y.

9. Числа, сумма цифр (по модулю) которого > N.

10. Числа, сумма цифр (по модулю) которого < N.

11. Числа, сумма цифр (по модулю) которого лежит в интервале от X до Y.

12. Числа, взятые по модулю, квадратный корень которых целое число.

где: N, X, Y - задается преподавателем.

Дата: 2019-12-10, просмотров: 370.