Download as pptx, pdf, or txt
Download as pptx, pdf, or txt
You are on page 1of 54

Структури даних, аналіз

і алгоритми комп'ютерної
обробки інформації
Лекції Бичкова Олексія
КРАХ ОСВІТИ – ЦЕ КРАХ
НАЦІЇ
Зміст
• Бінарні дерева пошуку
Бінарні дерева пошуку
Бінарне дерево - це ієрархічна структура
даних, в якій кожен вузол зберігає значення
та посилання на лівого та правого нащадка.
Бінарні дерева пошуку
Бінарне дерево пошуку - це бінарне дерево,
що має додаткові властивості: значення
лівого нащадка менше значення батька, а
значення правого нащадка більше значення
батька для кожного вузла дерева.
Тобто дані в бінарному дереві пошуку
зберігаються у відсортованому вигляді.
Бінарні дерева пошуку
Бінарні дерева пошуку
Бінарне дерево може бути представлено за допомогою
зв'язаної структури даних, у якій кожен вузол є
об'єктом. На додаток до атрибута ключа key і супутніх
даних кожен вузол містить атрибути left, right і
parent, які вказують на лівий і правий дочірні вузли і
батьківський вузол відповідно. Якщо дочірній або
батьківський вузол відсутні, поле містить значення
NUL. Єдиний вузол, вказівник якого дорівнює NUL, -
це кореневий вузол дерева.
Бінарні дерева пошуку
Тоді властивості бінарного дерева пошуку
запишуться так:
Нехай x є вузол бінарного дерева пошуку.
Якщо y є вузлом у лівому піддереві x, то
y.key<x.key. Якщо y є вузлом у правому
поддереві x, то y.key>x.key.
Бінарні дерева пошуку
Ця властивість дозволяє вивести всі ключі,
що знаходяться у дереві, у відсортованому
порядку за допомогою простого
рекурсивного алгоритму, що називається
центрованим (симетричним) обходом дерева.
Бінарні дерева пошуку
Цей алгоритм отримав дану назву у зв'язку з
тим, що ключ у корені піддерева виводиться
між значеннями ключів лівого піддерева та
правого піддерева.
Бінарні дерева пошуку
INORDER-TREE-WALK (x)
if (x != NUL)
INORDER-TREE-WALK (x.left)
print x.key
INORDER-TREE-WALK (x.right)
Бінарні дерева пошуку
Для бінарного дерева

отримаємо
2, 5, 5, 6, 7, 8
Бінарні дерева пошуку
Для обходу дерева з n вузлами потрібен час
Θ(n), оскільки після початкового виклику
процедура викликається рівно два рази для
кожного вузла дерева: один раз - для його
лівого дочірнього вузла і один раз - для
правого.
Бінарні дерева пошуку
Для обходу дерева з n вузлами потрібен час
Θ(n), оскільки після початкового виклику
процедура викликається рівно два рази для
кожного вузла дерева: один раз - для його
лівого дочірнього вузла і один раз - для
правого.
Пошук у бінарному дереві
TREE-SEARCH (x, k)
if (х == NUL або k == x.key)
return x
if (k<x.key)
return TREE-SEARCH(x.left, k)
else return TREE-SEARCH (x.right, k)
Пошук у бінарному дереві
Вузли, які ми проходимо при рекурсивному
пошуці, утворюють простий низхідний шлях
від кореня дерева, тому час роботи
процедури TREE-SEARCH дорівнює О(h), де
h — висота дерева.
Пошук у бінарному дереві
Цю процедуру можна записати ітеративно,
"розгорнувши" кінцеву рекурсію в цикл
while:
Пошук у бінарному дереві
ITERATIVE-TREE-SEARCH (Х, k)
while (x != NUL і k != x.key)
if (k<х.key)
х = х.left
else x = x.right
return x
Пошук у бінарному дереві
Мінімум та максимум
Елемент з мінімальним значенням ключа
завжди можна знайти, слідуючи за
дочірними вказівниками left від кореневого
вузла, доки не зустрінеться значення NUL.
Пошук у бінарному дереві
TREE-MINIMUM(х)
while (х.left != NUL)
x = x.left
return x

Псевдокод процедури TREE-MAXIMUM


симетричний
Пошук у бінарному дереві
TREE-MAXIMUM(х)
while (х.right != NUL)
x = x.right
return x
Пошук у бінарному дереві
Обидві процедури знаходять мінімальний
(максимальний) елемент дерева за час O(h),
де h — висота дерева, оскільки, як і в
процедурі TREE-SEARCH, послідовність
вузлів, що перевіряються, утворює простий
низхідний шлях від кореня дерева.
Пошук у бінарному дереві
Попередній та наступний елементи
Іноді для заданого вузла в бінарному дереві
пошуку потрібно визначити, який вузол
слідує за ним у відсортованій послідовності,
яка визначається порядком центрованого
обходу бінарного дерева, і який вузол
передує цьому.
Пошук у бінарному дереві
Якщо всі ключі різні, наступним по
відношенню до вузла x є вузол з найменшим
ключем, більшим за x.key. Структура
бінарного дерева пошуку дозволяє знайти
цей вузол навіть не виконуючи порівняння
ключів.
Пошук у бінарному дереві
TREE-SUCCESSOR(Z)
if (x.right != NUL)
return TREE-MINIMUM(x.right)
y= x.parent
while (y != NUL і x == у.right)
x=y
y = y.parent
return y
Пошук у бінарному дереві
Розглянемо цю процедуру на такому
прикладі:
Пошук у бінарному дереві
Код процедури TREE-SUCCESSOR розбивається
на дві частини. Якщо праве піддерево вузла x
непусте, то наступний за x елемент є крайнім
зліва вузлом у правому піддереві x, який
знаходиться викликом процедури TREE-
MINIMUM(x.right).
На рисунку наступним за вузлом з ключем 15 є
вузол з ключем 17.
Пошук у бінарному дереві
Для того щоб знайти наступний елемент у
випадку, коли x.right=NUL ми просто
піднімаємося вгору по дереву від x доти,
доки не зустрінемо вузол, який є лівим
дочірнім вузлом свого батька. І тоді бтько є
шуканий елемент. Так для елемента 13
наступним є елемент 15.
Пошук у бінарному дереві
Час роботи алгоритму TREE-SUCCESSOR у
дереві висотою h становить О(h), оскільки ми
або рухаємося простим шляхом вниз від
вихідного вузла, або простим шляхом вгору.
Процедура пошуку попереднього вузла в дереві
TREE-PREDECESSOR симетрична до процедури
TREE-SUCCESSOR І також має час роботи О(h).
Пошук у бінарному дереві
Вставка
Для вставки нового значення v у бінарне дерево
пошуку Т ми скористаємося процедурою TREE-
INSERT. Процедура отримує як параметр вузол z,
атрибути якого z.key = v, z.left=NUL та
z.right=NUL. Процедура таким чином змінює Т та
деякі поля z, та z виявляється вставленим у
коректну позицію дерева.
Пошук у бінарному дереві
TREE-INSERT (T, z)
y = NUL
x = Т.root
while (x != NUL)
у=х
if (z.key < x.key)
x = x.left
else x = x.right
Пошук у бінарному дереві
z.parent = y
if y == NUL
T.root=z // Дерево T було порожнім
elseif (z.key < y.key)
y.left = z
else y.right=z
Пошук у бінарному дереві
TREE-INSERT починає роботу з кореневого
вузла дерева і проходить простим низхідним
шляхом. Покажчик x відзначає шлях, що
проходить у пошуках NUL, який має бути
замінений вхідним елементом z.
Пошук у бінарному дереві
Після ініціалізації цикл while переміщує
вказівники x, y вниз по дереву, переміщаючись
ліворуч або праворуч залежно від результату
порівняння ключів z.key та x.key, доки x не стане
рівним NUL.
В цю позицію необхідно помістити елемент z.
Замикаючий покажчик y потрібен для того, щоб
знати, який вузол повинен бути змінений.
Пошук у бінарному дереві
Пошук у бінарному дереві
Видалення
Стратегія видалення вузла z із бінарного
дерева пошуку Т має три основні ситуації:
• Якщо у z немає дочірніх вузлів, ми просто
видаляємо його, вносячи зміни в його
батьківський вузол, а саме - замінюючи
дочірній вузол z на NUL.
Пошук у бінарному дереві
• Якщо у z лише один дочірній вузол, ми видаляємо
вузол z, створюючи новий зв'язок між батьківським і
дочірнім вузлами вузла z.
• Якщо у вузла z два дочірні вузли, то ми знаходимо
наступний за ним вузол, який має знаходитись в
правому піддереві z і який займає в дереві місце z.
Залишок вихідного правого піддерева z стає новим
піддеревом у, а ліве піддерево z стає новим лівим
піддеревом у.
Пошук у бінарному дереві
Процедура видалення даного вузла z з
бінарного дерева пошуку Т отримує як
аргумент вказівники на Т і z.
Пошук у бінарному дереві
• Якщо z не має лівого дочірнього вузла ми
замінюємо z його правим дочірнім вузлом, який
може бути (або не бути) NUL. Якщо правий дочірній
вузол z є NUL, то ми опиняємося в ситуації, коли у
вузла z немає дочірніх вузлів. Якщо правий дочірній
вузол z відмінний від NUL, то ми опиняємося у
ситуації, коли у вузла z є єдиний дочірній вузол,
який є правим дочірнім вузлом.
Пошук у бінарному дереві
Пошук у бінарному дереві
• Якщо z має лише один дочірній вузол, який є його
лівим дочірнім вузлом, то ми замінюємо z його
лівим дочірнім вузлом.
• Інакше z має лівий та правий дочірні вузли. Ми
знаходимо вузол у, наступний за р. Цей вузол
розташовується у правому піддереві z і не має лівий
дочірній вузл. Ми хочемо вирізати y з його
поточного положення і замінити їм в дереві вузол z.
Пошук у бінарному дереві
Пошук у бінарному дереві
• Якщо у є правим дочірнім вузлом z, то ми
замінюємо z на у, залишаючи недоторканим
правий дочірній по відношенню до у вузол.
Пошук у бінарному дереві
• Інакше y знаходиться у правому піддереві
вузла z, але не є правим дочірнім вузлом z. У
цьому випадку ми спочатку замінюємо його
власним правим дочірнім вузлом, а потім
замінюємо z на y.
Пошук у бінарному дереві
Пошук у бінарному дереві
TRANSPLANT заміняє піддерево з коренем у
вузлі u піддеревом з коренем у вузлі v;
батько вузла u стає батьком вузла v, який
стає відповідним дочірнім вузлом
батьківського по відношенню до вузла u.
Пошук у бінарному дереві
TRANSPLANT (T, u, v)
if (u.parent == NUL)
Т.root = v
elseif u== u.parent.left
u.parent.left = v
else u.parent.right = v
if v != NUL
v.parent = u.parent
Пошук у бінарному дереві
TRANSPLANT (T, u, v)
if (u.parent == NUL)
Т.root = v
elseif u== u.parent.left
u.parent.left = v
else u.parent.right = v
if v != NUL
v.parent = u.parent
Пошук у бінарному дереві
Спочатку обробляється випадок, коли u є коренем
Т. Інакше u є або лівим, або правим дочірнім
вузлом свого батька. Далі виконується оновлення
u.parent.left, якщо u є лівим дочірнім вузлом.
Якщо u є правим дочірнім вузлом. оновлюється
u.parent.right.
Ми допускаємо значення NUL для вузла v і далі
оновлюэмо v.parent, якщо v не NUL.
Пошук у бінарному дереві
TREE-DELETE (Т, z)
if (z.left == NUL)
TRANSPLANT (T, z, z.right)
elseif z.right == NUL
TRANSPLANT(T, z,z.left)
else y = TREE-MINIMUM (z.right)
Пошук у бінарному дереві
if y.parent != z
TRANSPLANT (T, y, y.right)
y.right=z.right
y.right.parent = у
TRANSPLANT (T, z, y)
y.left = z.left
y.left.parent = y
Пошук у бінарному дереві
Перші два рядки обробляють випадок, коли у вузла z
немає лівого дочірнього вузла, а два наступних рядки —
коли z є лівий дочірній вузол, але немає правого.
Потім працюємо із двома випадками, коли у z є два
дочірні вузли:
знаходимо вузол, наступний за z. Оскільки z має непусте
праве піддерево, наступний за z вузол має бути вузлом
цього піддерева з найменшим ключем; тому пошук вузла
здійснюється викликом TREE-MINIMUM (z.right).
Пошук у бінарному дереві
Як зазначалося раніше, вузол у немає лівого
дочірнього вузла. Ми хочемо вирізати y з його
поточного положення, після чого цей вузол
повинен замінити в дереві вузол z.
Якщо y є правим дочірнім вузлом z, то
заміняэмо вузол z на вузол y і заміняємо лівий
дочірній вузол y лівим дочірнім вузлом z.
Пошук у бінарному дереві
Якщо y не є правим дочірнім вузлом z,
виконується заміна y, як дочірнього вузла свого
батька правим дочірнім по відношенню до y
вузлом, і перетворення правого дочірнього вузла z
у правий дочірній вузол y.
Після цього заміняємо z, як дочірній вузол його
батька вузлом y, а лівим дочірнім вузлом y стає
лівий дочірній вузол z.
Пошук у бінарному дереві
TREE-DELETE виконується за час O(h) у
дереві висотою h.

You might also like