Розширюване дерево

Розширюване дерево (англ. splay tree) є двійковим деревом пошуку, у якому підтримується збалансованість. Це дерево належить до класу «саморегульованих дерев», які підтримують необхідний баланс галуження дерева, щоб забезпечити виконання операції пошуку, додавання і видалення за логарифмічний час від числа елементів, що зберігаються. Це реалізується без використання яких-небудь додаткових полів у вузлах дерева (як, наприклад, в Червоно-чорних деревах або АВЛ-деревах, де у вершинах зберігається, відповідно, колір вершини і глибина піддерева). Замість цього «розширювальні операції» (splay operation), частиною яких є повороти дерева, які виконуються при кожному зверненні до дерева. Облікова вартість з розрахунку на одну операцію з деревом складає .

Розширюване дерево
Тип Дерево
Винайдено 1985
Обчислювальна складність
у записі великого О
Середня Найгірша
Простір O(n) O(n)
Пошук O(log n) амортиз. O(log n)
Вставляння O(log n) амортиз. O(log n)
Видалення O(log n) амортиз. O(log n)

Розширюване дерево придумали Роберт Тарьян і Данієль Слейтор в 1985 році.

ОпераціїРедагувати

Splay (розширення)Редагувати

Основна операція дерева. Полягає в переміщенні вершини в корінь за допомогою послідовного виконання трьох, наведених нижче, операцій: Zig, Zig-Zig і Zig-Zag. Позначимо вершину, яку хочемо перемістити в корінь за x, її родича — p, а родича p (якщо існує) — g.

Zig: виконується, коли p є коренем. Дерево повертається по ребру між x та p. Існує лише для розбору крайнього випадку і виконується лише один раз в кінці, коли початкова глибина x була непарна.

Zig-Zig: виконується, коли x і p є лівими (або правими) синами. Дерево повертається по ребру між p та x.

Zig-Zag: виконується, коли x є правим сином, а p — лівим (чи навпаки). Дерево повертається по ребру між p та x, а потім — по ребру між x та g.

Search (пошук елемента)Редагувати

Пошук виконується як в звичайному двійковому дереві пошуку. При знаходженні елементу запускаємо Splay для нього.

Insert (додавання елемента)Редагувати

Запускаємо Splay від елементу, що додається, і підвішуємо дерева, що вийшли, за нього.

Delete (видалення елемента)Редагувати

Знаходимо елемент в дереві, робимо Splay для нього, робимо поточним деревом Merge його дітей.

Merge (об'єднання двох дерев)Редагувати

Для злиття дерев T1 і T2, в яких всі ключі T1 менше ключів в T2, робимо Splay для максимального елементу T1, тоді біля кореня T1 не буде правого дочірнього елемента. Після цього робимо T2 правим дочірнім елементом T1.

Split (розділення дерева на дві частини)Редагувати

Для розділення дерева знайдемо найменший елемент, більший або рівний x і зробимо для нього Splay. Після цього відрізуємо біля кореня лівого дочірнього елемента і повертаємо 2 дерева, що вийшли.

ПриміткаРедагувати

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

Розширюване дерево не володіє жодними явними функціями балансування, але процес скосу вузлів до кореня сприяє підтримці дерева в збалансованому вигляді.

АналізРедагувати

Амортизована вартість будь-якої операції на розширюваному дереві становить   де   це кількість вузлів у дереві. Будь-яка операція на дереві може зайняти   часу, але, як правило, також робить дерево більш збалансованим, так що з плином часу середня вартість операції є  [1]

Для отримання заявленої оцінки   використаємо метод потенціалів. По-перше визначимо вагу, суму і функцію рангу для кожного вузла:

  • Кожен вузол   має вагу   (з метою аналізу, може бути будь-якою)
  •   (вага вузла дорівнює сумі ваг усіх вузлів його піддерева)
  •  

Визначимо потенціал усього розширюваного дерева в будь-який момент   як суму рангів у дереві:

 

Потенціал вимірює наскільки збалансованим є дерево. Чим менше потенціал тим ліпше збалансоване дерево. Амортизаційна вартість операції складається з дійсної вартості плюс зміна потенціалу дерева.

Амортизована вартість одного кроку розширенняРедагувати

Нехай   буде ранг   перед розширенням і нехай   буде ранг   після розширення. Тоді амортизаційна вартість розширення

у випадку ZIG  
у випадках ZIG-ZIG і ZiG-ZAG  

Доведення: Позначимо амортизовану вартість як   і дійсну вартість як  

Розглянемо кожен з випадків окремо:

  1. ZIG
     
    Дійсна вартість дорівнює 1, тому що ми здійснюємо лише одне обертання, щоб перенести   в корінь. Оскільки   і   маємо:
     
  2. ZIG-ZIG
    Дійсна вартість є 2, бо ми виконуємо подвійне обертання. Використавши те, що   маємо:
     
     
     
    Для подальшого спрощення звернімо увагу на факт, що   — угнута функція, тобто для будь-яких   повинно виконуватись   Зауважимо, що   Через угнутість функції   маємо   по транзитивності   Отже,
     
  3. ZIG-ZAG аналогічно до ZIG-ZIG маємо:
     

Амортизаційний аналіз операції розширенняРедагувати

Наступні два наслідки слідують з попереднього аналізу.

Наслідок ІРедагувати

Нехай   буде вершиною розширюваного дерева перед виконанням операції розширення. Тоді амортизована вартість розширення вузла   становить  

Доведення: Амортизована вартість розширення в   дорівнює сумі вартостей всіх кроків розширення. Під час складання проміжні члени скорочуються і отримуємо, що розширення   є   Доданок 1 відповідає за можливість ZIG-обертання.

Цей аналіз незалежний від ваг у дереві. Припустимо, що ми встановили всі ваги в 1. Тоді найбільша можлива різниця між   і   дорівнює   від кількості вузлів у дереві. Отже, амортизована вартість розширення   є  

Наслідок ІІРедагувати

Дійсна вартість послідовності з   розширень становить  

Див. такожРедагувати

Сбалансовані дерева:

ПриміткиРедагувати

ДжерелаРедагувати

  • Daniel Sleator, Robert Tarjan. A data structure for dynamic trees. — Journal of Computer and System Sciences, 1983. — С. 262-391.