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


16

Враховуючи два дерева AVL T1 і T2 і значення таке, що , легко побудувати нове дерево AVL, що містить та значення в і в часі , де позначає висоту дерева (до тих пір, поки дерева зберігають свою висоту).trxT1,yT2,x<tr<ytrT1T2O(1+|h(T1)h(T2)|)h(T)T

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

Чи можливо це для трепетів або структур даних, схожих на підступ? Що робити, якщо ми не залишимо ?tr

Документ про обробку в Algorithmica показує, як це зробити за очікуваний час . Якщо є спосіб виконати очікуване приєднання O (1) на треупах (або структурах даних, подібних до трепа), приблизно з однаковим розміром (або кореневим пріоритетом), я думаю, можливо, можливо використовувати трюк Kaplan & Tarjan у завантаженні колючки для того, щоб зробити трепи (або структури, подібні до копання) з подвійно-логарифмічним з'єднанням.O(min(h(T1),h(T2)))


Ось якийсь код Haskell, який я написав, показує швидке з'єднання дерев AVL приблизно однакового розміру: haskell.pastebin.com/nfGV8Ffz
jbapple

Я сумніваюся, що це можливо, оскільки здається (без доказу), що очікувана глибина нового вузла (що містить значення t_r) є більш ніж постійною навіть у тому випадку, коли h (T_1) = h (T_2).
Цуйоші Іто

Tsuyoshi Ito: Я згоден, якщо ви призначите новому вузлу пріоритет так само, як ви призначите пріоритети для інших вузлів. Що робити, якщо призначити пріоритет, який гарантовано буде вище, ніж у кореневих вузлів? Це руйнує характер пріоритетів IID, але що робити, якщо ви позначаєте інші пріоритети як зміщені, як-небудь, як доріжки в стійких червоно-чорних деревах позначаються у кінцевих точках? Або що робити, якщо ці дані зберігаються лише у листах треупа і виконують з'єднання без t_r?
jbapple

Вузли в трепах з n нащадками я залишив нащадків з вірогідністю 1 / n. Це може сприяти тривалим часом злиття навіть для трепок однакового розміру - для вибору нового кореня потрібно переходити до нього, що, оскільки середня глибина дерева є Theta (lg n), також займає Theta (lg n) час. Що робити, якщо вузол зіткнення з n нащадками я залишив дітей з вірогідністю (n select i) / 2 ^ n, а значення зберігаються лише на листках, як у B + -древі. Потім об'єднання двох однакових розмірів перерозподіляє невелику кількість елементів від одного дерева до іншого в очікуванні.
jbapple

Якщо мої підрахунки вірні, очікувана кількість перерозподілених елементів - це Theta (sqrt n), який, припускаючи, що все інше могло бути відпрацьовано (як властивість пошуку пальцем), все-таки забирає тета (lg n) час у очікуванні. Що з використанням ще більш жорсткого розподілу?
jbapple

Відповіді:


3

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

Точне твердження, яке я висловлю, полягає в тому, що для здійснення такого злиття за двома однаковими розмірами трейд із випадковими пріоритетами потрібно оновити покажчики в очікуванні.Θ(logn)

Ось приблизний ескіз:

Розгляньте кількість покажчиків, які вам доведеться змінити, очікуючи на виконання операції. Простіше довести обмеження якщо ми не вставимо t r, а просто зробимо об'єднання T 1 і T 2 . Розглянемо правий хребет S 1 з T 1 і лівий хребет S 2 з T 2 . Пофарбуйте елементи S 1 червоного та елементи S 2 синього. Порядок S 1S 2Θ(logn)trT1T2S1T1S2T2S1S2S1S2за пріоритетом. Ми повинні змінювати вказівник щоразу, коли колір змінюється в цій послідовності. Оскільки обидва колючки мають розмір з високою ймовірністю, а пріоритети - випадкові, не надто важко зрозуміти, що # зміни кольору в послідовності також Θ ( log n ) . Тому нам потрібно оновити Θ ( log n ) покажчики для злиття (без додавання t r ).Θ(logn)Θ(logn)Θ(logn)tr

Тепер додавання під час злиття насправді не дуже допомагає. Кількість змін вказівника в цьому випадку може бути нижньо обмежена наступним чином: Порядок S 1S 2{ t r } за пріоритетом. Видаліть у послідовності все менше, ніж t r . Тоді # зміна кольору в отриманій послідовності - наша нижня межа. Оскільки t r має випадковий пріоритет, очікувана висота підкореневого дерева, вкоріненого в ньому в кінцевій treap, дорівнює O ( 1 ) , тому в ньому є лише O ( 1 ) вузли S 1trS1S2{tr}trtrO(1)O(1) з нижчим пріоритетом, ніж він у очікуванні, тому ми втратили лише зміни O ( 1 ) вказівника нижньої межі при додаванні t r .S1S2O(1)tr

Тепер, маючи на увазі, ймовірно, існує спосіб отримати структуру даних "схожий на трейп", яка дозволяє постійно очікувати злиття часу.


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

Дякую за вашу відповідь. Я змінив назву та текст питання, щоб бути менш неоднозначним.
jbapple

1

Оновлення: див. Нижче для оновлення про некоректність цієї операції приєднання

Ось дуже приблизний ескіз можливого рішення:

Я думаю, що я можу вирішити цю проблему, використовуючи тип випадково врівноваженого B +-дерева. Як і трави, ці дерева мають унікальне уявлення. На відміну від трепів, вони зберігають деякі ключі кілька разів. Можна виправити, що за допомогою хитрості "Biased Trees" від Bent et al зберігати кожну клавішу можна лише на найвищому (тобто найближчому до кореня) рівні, на якому вона відображається)

Дерево для впорядкованого набору унікальних значень створюється шляхом спочатку асоціювання кожного значення з потоком бітів, аналогічно тому, як кожне значення в трейпі асоціюється з пріоритетом. Кожен вузол у дереві містить і ключ, і бітовий потік. Крім листяних вузлів, крім того, є натуральне число, що вказує на висоту дерева, вкоріненого у цьому вузлі. Внутрішні вузли можуть мати будь-яку ненульову кількість дітей. Як і B + -трець, кожен непересічний шлях від кореня до листка має однакову довжину.

vkivki+1vvi1vi

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

Наступний список клавіш і (початок) потоків бітів представлений деревом під ним. У префіксах бітових потоків, '.' означає будь-який шматочок. Тобто, будь-який потік бітів для ключа A з 0, в першу чергу, створює те саме дерево, що і будь-яке інше, припускаючи, що жоден бітовий потік іншого ключа не відрізняється.

A 0...
B 00..
C 10..
D 0...
E 0011
F 1...
G 110.
H 0001


        ____H____
       /         \
      E           H
      |          / \
    __E__       G   H
   /  |  \      |   |
  B   C   E     G   H
 / \  |  / \   / \  |
A   B C D   E F   G H

Кожна дитина конкретного внутрішнього вузла має однаковий біт в першу чергу свого бітового потоку. Це називається батьківським кольором - 0 - червоний, 1 - зелений. Дитина має "аромат" залежно від першого шматочка її потік - 0 - це вишня, 1 - м'ята. Листя мають аромати, але не мають кольору. За визначенням, вишневий вузол не може мати зеленого батька, а м'ятний вузол не може мати батьківського червоного кольору.

n21n (n1i1)(n+1)/2n234nO(lgn)

Щоб з'єднати два дерева однакової висоти, спочатку перевірте, чи є їхні корені одного кольору. Якщо так, відірвіть від лівого кореня його найбільш праву дитину, а від правого корінь - ліву найбільшу дитину, а потім рекурсивно з'єднайте ці два дерева. У результаті вийде дерево однакової висоти або на один високий, оскільки дерева мають однаковий аромат (див. Нижче). Якщо результат рекурсивного з’єднання двох дерев має такий самий зріст, що і двоє відрізаних дітей, зробіть це середнім дочкою кореня з рештою дітей лівого кореня перед ним та рештою дітей правого кореня після нього. Якщо вона вище на 1, зробіть її дітей середніми дітьми кореня з рештою дітей лівого кореня перед ним, а рештою дітей правого кореня після нього. Якщо коріння мають різні кольори, перевірте, чи мають вони однаковий аромат. Якщо вони це роблять, дайте їм нового батьків з ключем і бітовим потоком правильного кореня, вивівши його перший біт. Якщо цього немає, дайте кожному кореневі нового батьківського з ключем і бітовим потоком старого кореня (витісняючи кожен перший біт), а потім рекурсивно приєднуйтесь до цих дерев.

1/21/2O(1)1/4, а наступні рекурсивні дзвінки завжди на деревах з різними кольорами, тому застосовується однаковий аналіз.

1/2O(1)

O(1)

a 01110
b 110..
c 10...
d 00000

Дерево, виготовлене за допомогою [a,b]висоти 2, дерево, виготовлене за допомогою, [c,d]має висоту 2, а дерево, виготовлене за допомогою joinEqual (tree [a,b]) (tree [c,d])висоти 3. Проте дерево, виготовлене за допомогою, [a,b,c,d]має висоту 5.

Ось код, який я використав, щоб знайти цю помилку .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.