Розширюване дерево | ||
---|---|---|
Тип | Дерево | |
Винайдено | 1985 | |
Обчислювальна складність у записі великого О | ||
Середня | Найгірша | |
Простір | O(n) | O(n) |
Пошук | O(log n) | амортиз. O(log n) |
Вставляння | O(log n) | амортиз. O(log n) |
Видалення | O(log n) | амортиз. O(log n) |
Розширюване дерево (англ. splay tree) є двійковим деревом пошуку, у якому підтримується збалансованість. Це дерево належить до класу «саморегульованих дерев», які підтримують необхідний баланс галуження дерева, щоб забезпечити виконання операції пошуку, додавання і видалення за логарифмічний час від числа елементів, що зберігаються. Це реалізується без використання яких-небудь додаткових полів у вузлах дерева (як, наприклад, в Червоно-чорних деревах або АВЛ-деревах, де у вершинах зберігається, відповідно, колір вершини і глибина піддерева). Замість цього «розширювальні операції» (splay operation), частиною яких є повороти дерева, які виконуються при кожному зверненні до дерева. Облікова вартість з розрахунку на одну операцію з деревом складає .
Розширюване дерево придумали Роберт Тарьян і Данієль Слейтор в 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
Доведення: Позначимо амортизовану вартість як і дійсну вартість як
Розглянемо кожен з випадків окремо:
- ZIG
- Дійсна вартість дорівнює 1, тому що ми здійснюємо лише одне обертання, щоб перенести в корінь. Оскільки і маємо:
- ZIG-ZIG
- Дійсна вартість є 2, бо ми виконуємо подвійне обертання. Використавши те, що маємо:
- Для подальшого спрощення звернімо увагу на факт, що — угнута функція, тобто для будь-яких повинно виконуватись Зауважимо, що Через угнутість функції маємо по транзитивності Отже,
- ZIG-ZAG аналогічно до ZIG-ZIG маємо:
Амортизаційний аналіз операції розширення
Наступні два наслідки слідують з попереднього аналізу.
Наслідок І
Нехай буде вершиною розширюваного дерева перед виконанням операції розширення. Тоді амортизована вартість розширення вузла становить
Доведення: Амортизована вартість розширення в дорівнює сумі вартостей всіх кроків розширення. Під час складання проміжні члени скорочуються і отримуємо, що розширення є Доданок 1 відповідає за можливість ZIG-обертання.
Цей аналіз незалежний від ваг у дереві. Припустимо, що ми встановили всі ваги в 1. Тоді найбільша можлива різниця між і дорівнює від кількості вузлів у дереві. Отже, амортизована вартість розширення є
Наслідок ІІ
Дійсна вартість послідовності з розширень становить
Див. також
Сбалансовані дерева:
Примітки
- ↑ Розширюване дерево [Архівовано 19 березня 2015 у Wayback Machine.] на MIT OpenCourseWare
Джерела
- Т. Кормен; Ч. Лейзерсон; Р. Рівест; К. Стайн (2009) [1990]. Вступ до алгоритмів (вид. 3rd). MIT Press і McGraw-Hill. ISBN 0-262-03384-4.
- Daniel Sleator, Robert Tarjan. A data structure for dynamic trees. — Journal of Computer and System Sciences, 1983. — С. 262-391.