Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Алгоритмы и структуры данных / методичка структуры данных_задания.docx
Скачиваний:
54
Добавлен:
12.05.2015
Размер:
381.84 Кб
Скачать

3.4.2. Ідеально збалансовані дерева

Дерево має назву ідеально збалансованого, якщо для кожного вузла кількість вузлів у лівому та правому піддеревах відрізняється не більше ніж на один.

Припустимо, що необхідно побудувати дерево з n вузлами та мінімальною висотою. Значення вузлів – n чисел.

Щоб досягнути мінімальної висоти при заданому числі вузлів, треба розміщувати максимально можливе число вузлів на усіх рівнях, крім самого нижнього. Для цього вузли, які надходять, розміщуються нарівно зліва та зправа від кожного вузла.

Правило рівномірного розподілу при відомому числі вузлів n краще за все формулюється за допомогою рекурсії:

1. Взяти один вузол як корень.

2. Побудувати ліве піддерево з nl = n div 2 вузлами тим же засобом.

3. Побудувати праве піддерево з nr = n-nl-1 вузлами тим же засобом.

Припустимо, що маємо такі вхідні дані для дерева з 21 вузлом:

8 9 11 15 19 20 21 7 3 2 1 5

6 4 13 14 10 12 17 16 18

У відповідності з правилом розподілу за допомогою поданої нижче програми можна побудувати дерево (за правилом: взяти один вузол, побудувати ліве піддерево з nl=n div 2 вузлами тим же засобом і праве з nr=n-nl-1 тим же засобом).

{ Побудова ідеально збалансованого дерева з n вузлами}

Uses Crt;

Type

ref=^node;

node=Record

key : integer;

left : ref;

right : ref;

End;

Var

n : integer;

root : ref;

{-------Побудова дерева -----}

Function Tree (n:integer):ref;

Var

newnode : ref;

x, nl, nr : integer;

Begin

If n=0 Then Tree:=Nil

Else

Begin

nl:=n div 2;

nr:=n-nl-1;

Writeln(‘ вузол’);

Read (x);

New (newnode);

With newnode^ Do

Begin

key:=x;

left:=Tree(nl);

right:=Tree(nr);

End;

Tree:=newnode

End;

End; {Tree}

{----------------------------------------}

Procedure PrintTree (t:ref; h:integer);

Var

i : integer;

Begin

If t <> Nil Then

With t^ Do

Begin

PrintTree (right, h+1);

For i:=1 To h Do Write (‘ ‘);

Writeln (key);

PrintTree (left, h+1)

End

End; {PrintTree}

{----------------------------------------}

Begin

ClrScr;

Writeln (‘Введіть кількість вузлів’);

Readln (n);

root:=Tree(n);

Writeln (‘Побудоване дерево’);

PrintTree(root,0);

Repeat Until KeyPressed;

End.

Процедура друкування дерева PrintTree є прикладом процедури, яка здійснює інфіксний обхід дерева.

Наведена нижче процедура Htree є прикладом префіксного обходу дерева. Змінна n відображує рівень дерева, змінна h – кількість вузлів на заданому рівні nn.

Procedure Htree(t:ref; n:integer; Var h:integer);

Begin

If t <> Nil Then

With t^ DO

Begin

n:=n+1;

If n=nn Then h:=h+1;

Htree(left,n,h);

Htree(right,n,h);

End

End;

3.4.3. Дерева пошуку

Якщо дерево організоване таким чином, що для кожного вузла t усі ключі у лівому піддереві менші ключа t, а ключі у правому піддереві більше ключа t, це дерево має назву дерева пошуку.

У дереві пошуку можна знайти місце кожного ключа, рухаючись, починаючи від кореня та переходячи на ліве або праве піддерево у залежності від значення його ключа.

Приклад.

8 9 11 15 19 20 21 7 3 2

1 5 6 4 13 14 10 12 17 16 18

Пошук по дереву з включенням

Можливості техніки динамічного розміщення змінних цікаво демонструвати та доцільно використовувати у задачах, де структура даних змінюється під час виконання програми, тобто для випадків, коли інша організація даних, наприклад, масиви, не можуть бути використані.

Розглянемо випадок зростаючого дерева.

Дерево будується з ключів, які ще не зустрічались. Починаючи з порожнього дерева, кожний ключ шукається у дереві, якщо відсутній – вставляється. Ця задача має назву пошуку по дереву з включенням {якщо є такий ключ, не включати, а тільки збільшити на одиницю лічильник частоти входжень у дерево даного ключа, інакше – включити}.

{Пошук з включенням по двійковому дереву}

Uses Crt;

Type

ref = ^Wword;

Wword = Record

key : integer;

count : integer;

left, right : ref;

End;

Var

root : ref;

k : integer;

Procedure PrintTree (w:ref; l:integer);

Var

i : integer;

Begin

If w<>Nil Then

With w^ Do

Begin

PrintTree (right, l+1);

For i:=1 To l Do Write (‘ ‘);

Writeln (key);

PrintTree (left,l+1);

End

End;

Procedure Search (x:integer; Var p :ref);

Begin

If p=Nil Then

Begin {слова немає в дереві, включити його}

New(p);

With p^ Do

Begin

key:=x;

count:=1;

left:=Nil;

right:=Nil

End

End

Else

If x<p^.key Then Search(x, p^.left)

Else If x>p^.key Then Search(x, p^.right)

Else p^.count:= p^.count +1

End ;{Search}

{------------------------------------------------------}

Begin

ClrScr;

root:=Nil;

Writeln (‘Введіть ключі’);

Repeat

Read(k);

Search(k,root);

Until k=0;

Writeln(‘ Дерево пошуку’);

PrintTree (root,0);

Repeat Until KeyPressed

End.

Параметр p передається як параметр – змінна, а не як параметр – значення, тому у випадку включення елемента вказівник, який був порожнім, отримує значення нової вершини і далі рекурсивно змінюється.

Алгоритм створення дерева пошуку можна застосувати і для сортування. В задачах, де потрібен і пошук, і сортування, рекомендується цей алгоритм. Він часто застосовується у трансляторах та програмах роботи з банками даних для організації об’єктів, які потрібно зберігати і шукати у пам’яті.

Вилучення вузла з дерева

Розглянемо випадок вилучення вузла з ключем x із дерева з упорядкованими ключами.

Якщо елемент є термінальним вузлом або має одного нащадка, вилучити його – означає замінити вказівник на порожній або на вказівник на нащадка. Якщо вилучається елемент з двоми нащадками – виникає проблема, так як не можна посилатися одним вказівником на два напрямки.

В цьому випадку елемент, який треба вилучити, необхідно замінити або на самий правий елемент його лівого піддерева, або на самий лівий елемент його правого піддерева.

Вилучення Вилучення елемента термінального з одним нащадком(15) елемента(13)

Вилучення елемента з двома нащадками

Наведена нижче процедура вилучення обробляє відповідно чотири випадки:

1. Елемент з заданим ключем відсутній.

2. Елемент з заданим ключем є термінальним вузлом.

3. Елемент з заданим ключем має не більше одного нащадка.

4. Елемент з заданим ключем має двох нащадків.

{Вилучення вузла з дерева}

Procedure Delet (x:integer; Var p:ref);

Var

q : ref;

Procedure Del (Var r:ref);

Begin

If r^.right<>Nil Then Del(r^.right)

Else

Begin

q^.key:=r^.key;

q:=r; r:=r^.left

End

End; {Del}

Begin

If p=Nil Then Writeln (‘Слова немає в дереві’)

Else

If x < p^.key Then Delet (x, p^.left)

Else

If x > p^.key Then Delet (x, p^.right)

Else

Begin { вилучення p^ }

q:=p;

If q^.right = Nil Then p:=q^.left

Else

If q^.left = Nil Then p:=q^.right

Else

Del (q^.left);

End

End; {Delet}