Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Метода по ОАиП.doc
Скачиваний:
12
Добавлен:
11.05.2015
Размер:
3.21 Mб
Скачать

15.5.2. Основные алгоритмы работы с бинарным деревом

В общем случае при работе с такими структурами необходимо уметь:

– построить (создать) дерево;

– вставить новый элемент;

– обойти все элементы дерева, например, для просмотра или выполнения некоторой операции;

– выполнить поиск элемента с указанным значением в узле;

– удалить заданный элемент.

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

15.5.3. Формирование дерева

Например, имеется последовательность ключей 17, 18, 6, 5, 9, 23, 12, 7, 8, тогда построенное по ним дерево будет выглядеть следующим образом:

15.5.4. Вставка нового элемента

Для того чтобы вставить новый элемент в дерево, необходимо найти для него место. Для этого, начиная с корня, сравниваем значения узлов (Tree->info)со значением нового элемента (b). Еслиb info, то идем по левой ветви, в противном случае – по правой ветви. Когда дойдем до узла, из которого не выходит нужная ветвь для дальнейшего поиска, это означает, что место под новый элемент найдено.

Путь поиска места в построенном дереве для числа 11:

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

Tree*Make(Tree*Root) {

Tree*Prev, *t; //Prevродитель (предыдущий) текущего элемента

intb,find;

if(Root==NULL) { // Если дерево не создано

printf("\n Input Root : ");

scanf(“%d”, &b);

Root=List(b); // Установили указатель на корень

}

//================ Добавление элементов =================

while(1) {

printf("\nInputInfo: ");scanf(“%d”, &b);

if(b<0)break; // Признак выхода число < 0

t=Root; // Текущий указатель на корень

find = 0; // Признак поиска

while ( t && ! find) {

Prev = t;

if(b==t->info)

find= 1; // Ключи должны быть уникальны

else

if ( b < t -> info ) t = t -> Left;

else t = t -> Right;

}

if (!find) { // Нашли место с адресом Prev

t=List(b); // Создаем новый узел

if(b<Prev->info) // и присоединяем его, либо

Prev->Left=t; // на левую ветвь,

elsePrev->Right=t; // либо на правую ветвь

}

} // Конец цикла

returnRoot;

}

Функция List предназначена для создания нового элемента – листа:

Tree* List(int i) {

Tree *t = (Tree*) malloc (sizeof(Tree));

t -> info = i;

t -> Left = t -> Right = NULL;

returnt;

}

Участок кода с обращением к функции Createбудет иметь следующий вид:

struct Tree { // Декларация шаблона

int info;

Tree *Left, *Right;

};

void main()

{

Tree *Root = NULL; // Указатель корня

Root = Make(Root);

15.5.5. Удаление узла

При удалении узла из дерева возможны три ситуации в зависимости от того, сколько сыновей (потомков) имеет удаляемый узел.

1. Удаляемый узел является листом – просто удаляем ссылку на него. Приведем пример схемы удаления листа с ключомkey:

2. Удаляемый узел имеет только одного потомка, т.е. из удаляемого узла выходит ровно одна ветвь. Пример схемы удаления узлаkey, имеющего одного сына:

3. Удаление узла, имеющего двух сыновей, значительно сложнее рассмотренных выше. Еслиkey– удаляемый узел, то его следует заменить узломw, который содержит либо наибольший ключ (самый правый, у которого указательRightравенNULL) в левом поддереве, либо наименьший ключ (самый левый, у которого указательLeftравенNULL) в правом поддереве.

Используя первое условие, находим узел w, который является самым правым узлом поддереваkey, у него имеется только левый сын:

В построенном ранее дереве удалим узел key (6). Используем второе условие, т.е. ищем самый левый узел в правом поддереве – это узел w (указательLeftравенNULL):

Функция удаления узла по заданному ключу key может иметь вид

Tree* Del(Tree *Root, int key) {

Tree *Del, *Prev_Del, *R, *Prev_R;

// Del,Prev_Del–удаляемый элемент и его предыдущий (родитель);

// R,Prev_R–элемент, на который заменяется удаленный, и его родитель;

Del = Root;

Prev_Del = NULL;

// ===== Поиск удаляемого элемента и его родителя по ключу key=====

while (Del != NULL && Del -> info != key) {

Prev_Del = Del;

if (Del->info > key) Del = Del->Left;

else Del = Del->Right;

}

if (Del == NULL) { // Элемент не найден

puts("\n NO Key!");

return Root;

}

// ============ Поиск элемента Rдля замены =================

if (Del -> Right == NULL) R = Del->Left;

else

if (Del -> Left == NULL) R = Del->Right;

else{

// Ищем самый правый узел в левом поддереве

Prev_R = Del;

R = Del->Left;

while (R->Right != NULL) {

Prev_R = R;

R=R->Right;

}

// Нашли элемент для замены Rи его родителяPrev_R

if( Prev_R == Del)

R->Right = Del->Right;

else {

R->Right = Del->Right;

Prev_R->Right = R->Left;

R->Left = Prev_R;

}

}

if (Del== Root) Root = R; // Удаляя корень, заменяем его на R

else

// Поддерево Rприсоединяем к родителю удаляемого узла

if (Del->info < Prev_Del->info) Prev_Del->Left = R; // на левую ветвь

else Prev_Del->Right = R; // на правую ветвь

printf("\n Delete element %d \n", Del->info);

free(Del);

returnRoot;

}

Участок программы с обращением к данной функции будет иметь вид

printf("\n Input Del Info : ");

scanf(“%d”, &key);

Root = Del(Root, key);