
- •1. Сортування
- •1.1. Сортування масивів
- •1. Сортування простими включеннями;
- •2. Сортування простим вибором;
- •1.1.1. Сортування простими включеннями
- •1.1.2. Сортування простим вибором
- •1.1.3. Сортування простим обміном (засіб “бульбашки”)
- •1.1.4. Шейкер-сортування
- •1.1.5. Швидке сортування
- •1.2. Сортування масива рядків
- •1.3. Сортування файлів
- •2. Рекурсивні алгоритми
- •2.1. Алгоритми з поверненням
- •2.1.1. Шахова задача про хід коня
- •2.1.2. Шахова задача про вісім ферзів
- •3. Динамічні інформаційні структури
- •3.1. Динамічні змінні. Вказівники
- •3.1.1. Засоби створення та використання динамічних даних
- •3.2. Рекурсивні типи даних
- •3.3. Списки
- •3.3.2. Двозв’язні та кiльцевi списки
- •3.3.3. Черги і стеки
- •3.4. Деревовидні структури
- •3.4.1. Бінарні дерева
- •3.4.2. Ідеально збалансовані дерева
- •3.4.3. Дерева пошуку
- •3.4.4. Збалансовані дерева (авл-дерева)
- •4. Завдання до лабораторних та контрольних робіт.
- •4.1. Сортування.
- •4.2. Списки.
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}