Двійкові обертання дерев


16

Збалансовані дерева бінарного пошуку є важливими для гарантування O (log n) пошуку (або подібних операцій). У динамічному середовищі, де безліч клавіш вставлено і / або видалено, дерева можуть перерости у пов’язані списки, які є жахливими для пошуку. Таким чином, існують різні види самоврівноважуючих бінарних дерев, які протидіють цьому ефекту (наприклад, AVL-дерева чи хитрі дерева ). Ці дерева засновані на різних видах обертів, які врівноважують дерево.

Обертання

У цьому виклику ми розглянемо лише поодинокі праві обертання; таке обертання (ліве обертання було б симетричним) виглядає приблизно так:

    5            3
   / \          / \
  3   6   =>   1   5
 / \              / \
1   4            4   6

Якщо будь-яке з листя 1, 4або 6ліве або праве під деревце, обертання просто утримало б їх там. Якщо це піддерево більшого дерева, ми просто "відріжемо його" на вузлі 5і "прикріпимо" повернене дерево (тепер вузол 3) до цього вузла.

Виклик

Дано дерево бінарного пошуку 1 та клавішу праворуч поверніть дерево на цьому вузлі, як описано вище. Ключовим моментом у наведеному вище прикладі буде 5.

Правила та введення / виведення

  • Ви можете використовувати будь-який тип для клавіш до тих пір, поки між клавішами на ваш вибір та типовими тестами є біекція
  • ви можете вибрати будь-яке представлення для двійкових дерев, якщо немає двозначності (наприклад [3,[]], неоднозначно, якщо не вказано інше), і це природно для вашої мови вибору
  • оскільки вхід завжди буде двійковим деревом пошуку, не буде дублікатів ключів
  • ви можете припустити, що ключ міститься в дереві
  • ви можете припустити, що у вузла, що містить ключ, є ліва дитина
  • ви не можете припустити потрібне піддерево під наданим ключем
  • ви можете не припускати, що дерево не є рівноважним перед обертанням
  • ви можете не припускати, що дерево врівноважується після обертання
  • Ви можете використовувати будь-який метод вводу / виводу за замовчуванням
  • ваше подання може бути функцією, що повертає дерево або повною програмою друкує рішення

Тестові справи

Ці приклади являють собою дерево наступним чином

  • якщо це лист: []
  • якщо це дерево з ключем, xі обидва підряди - це листя:[x]
  • якщо це дерево з ключем xта підрядками left right:[x,left,right]

Перший приклад - поданий у розділі Обертання . Якщо вам чомусь потрібне графічне зображення, тут ви переходите 2 .

5 [5,[3,[1],[4]],[6]]  ->  [3,[1],[5,[4],[6]]]
5 [5,[3,[1],[4]],[]]  ->  [3,[1],[5,[4],[]]]
5 [5,[3,[],[4]],[6]]  ->  [3,[],[5,[4],[6]]]
5 [5,[3,[1],[]],[]]  ->  [3,[1],[5]]
4 [8,[4,[2,[1],[3]],[6,[5],[7]]],[12,[10,[9],[11]],[14,[13],[15]]]]  ->  [8,[2,[1],[4,[3],[6,[5],[7]]]],[12,[10,[9],[11]],[14,[13],[15]]]]
8 [10,[8,[6,[4,[2,[],[3]],[5]],[7]],[9]],[11]]  ->  [10,[6,[4,[2,[],[3]],[5]],[8,[7],[9]]],[11]]
10 [10,[8,[6,[4,[2,[],[3]],[5]],[7]],[9]],[11]]  ->  [8,[6,[4,[2,[],[3]],[5]],[7]],[10,[9],[11]]]
9 [6,[3,[2],[5]],[9,[8],[12,[11],[15,[14],[]]]]]  ->  [6,[3,[2],[5]],[8,[],[9,[],[12,[11],[15,[14],[]]]]]]
7 [7,[5,[3,[1],[4]],[6]],[8]]  ->  [5,[3,[1],[4]],[7,[6],[8]]]
15 [17,[9,[5,[2,[0],[4]],[8]],[15,[13,[11,[10],[12]],[14]],[16]]],[40,[27,[21,[19,[18],[20]],[24,[22],[25]]],[28]],[44,[42,[41],[]],[51,[47],[59,[55],[61]]]]]]  ->  [17,[9,[5,[2,[0],[4]],[8]],[13,[11,[10],[12]],[15,[14],[16]]]],[40,[27,[21,[19,[18],[20]],[24,[22],[25]]],[28]],[44,[42,[41],[]],[51,[47],[59,[55],[61]]]]]]
21 [17,[9,[5,[2,[0],[4]],[8]],[15,[13,[11,[10],[12]],[14]],[16]]],[40,[27,[21,[19,[18],[20]],[24,[22],[25]]],[28]],[44,[42,[41],[]],[51,[47],[59,[55],[61]]]]]]  ->  [17,[9,[5,[2,[0],[4]],[8]],[15,[13,[11,[10],[12]],[14]],[16]]],[40,[27,[19,[18],[21,[20],[24,[22],[25]]]],[28]],[44,[42,[41],[]],[51,[47],[59,[55],[61]]]]]]

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

2: щоб запобігти гниттю посилань, я вклав їх як коментар

Відповіді:


8

Haskell , 93 92 84 83 82 байт

data B=B[B]Int|L
k!B[l@(B[x,y]a),r]n|k<n=B[k!l,r]n|k>n=B[l,k!r]n|1>0=B[x,B[y,r]k]a

Дякуємо @BMO, @alephalpha та @Laikoni за кожен байт та @nimi за вісім байтів!

Спробуйте в Інтернеті!


Використання data B=B[B]Intдозволить заощадити ще кілька байт.
Лайконі

@Laikoni лише один байт Я думаю, але я візьму його
Angs

Ви можете зберегти 2 байти, спочатку об'єднавши два випадки, k<n=B[k!l,r]nі k>n=B[l,k!r]n, в один:, k/=n=B[k!l,k!r]nа потім додавши, k!x=xщоб зразок відповідності був вичерпним.
Радек

5

Vim , 25 байт

Бере вхід у буфер - пробіл, розділений клавішею та деревом. Очікується, що дерево буде представлено таким чином:

  • лист: []
  • вузол з ключем k, ліва дитина <left>та права дитина <right>:[ k <left><right>]

Не kважливі простори навколо ключа , такі, що рішення працює для довільних дерев.

"adw/ <C-r>a⏎3dw%l"apr[%xl%i]

Спробуйте в Інтернеті!

Пояснення

"adw                           " delete the key and trailing space, keep in register a
    / <C-r>a⏎                  " move cursor to the key surrounded with spaces
             3dw               " remove key and [ (move left node to top)
                %l             " move cursor to the right subtree
                  "ap          " insert key there
                     r[        " insert a [ (appending subtree to key)
                       %       " move to the end of new left subtree
                        x      " remove ] (fix parentheses)
                         l%    " move to the end of new right subtree
                           i]  " insert ] (fix parentheses)

Попередній перегляд

Ось попередній перегляд першого тестового випадку, згенерованого Лінном за допомогою цього сценарію :

                       Попередній перегляд Vim


3

Мова Вольфрама (Mathematica) , 30 байт

#2/.a_~b_~c_~#~d_:>b[a,c~#~d]&

Спробуйте в Інтернеті!

Дерево представлено таким чином:

  • якщо це лист: $(ви можете замінити його будь-яким значенням, яке не є ключовим)
  • якщо це дерево з ключем xта підрядками left right:x[left,right]

Наприклад, дерево в першому тестовому випадку представлено символом 5[3[1[$,$],4[$,$]],6[$,$]].

Пояснення:

#2                                the second input
  /.                              replace
    a_~b_~c_~#~d_                 #[b[a,c],d], where # is the first input
                 :>               by
                   b[a,c~#~d]     b[a,#[c,d]]
                             &    define a function

3

Лист звичайний, 146 байт

(defun r(k a)(cond((not a)a)((=(car a)k)`(,(caadr a),(cadadr a)(,(car a),(car(cddadr a)),(caddr a))))(t`(,(car a),(r k(cadr a)),(r k(caddr a))))))

Спробуйте в Інтернеті або перевірте всі тести!

Дерево представлено таким чином:

  • порожнє дерево представлено як nil(або еквівалентно у Common Lisp як порожній список ())
  • не порожнє дерево представлене у вигляді списку з трьох елементів (node left-subtree right-subtree) (тому лист Lпредставлений як (L nil nil)).

2

JavaScript (Node.js) , 70 байт

n=>f=a=>n-a[0]?(a[i=n<a[0]?1:2]=f(a[i]),a):(i=a[1],a[1]=i[2],i[2]=a,i)

Спробуйте в Інтернеті! Посилання включає тестові випадки. Усі вузли повинні мати лівий і правий записи, але вони можуть вказувати, []що на цій стороні немає піддерева. Як абревіатура тестовий набір використовує, l(N)щоб вказати, що Nце аркуш, і l(N,L)вказати, що Nє ліве піддерево, Lале праворучне піддерево як на вході, так і на виході.



1

Желе , 24 байти

ñ
Ḣ,1ịṪƊṭ@ṪṭḢð{Ḣ;ç€ɗ¹¡i?

Спробуйте в Інтернеті!

Попередження: Зазвичай верхня лінія не повинна існувати, а нижня повинна мати а ß, а не ç. Однак розумні хитрощі ланцюжків і ßне виходять разом, завдякиßзмінна артія. Технічно я міг би все-таки пропустити верхній рядок, але тоді результат мав би бути повноцінною програмою, оскільки в іншому випадку вона повинна бути здатна бути включена як власна лінія всередині будь-якої програми, що неможливо, якщо ви щастить Це означає, що, на жаль, результат мав би неоднозначне представлення, оскільки, коли ви подаєте повну програму, фактично підраховується вихід, а не те, що технічно отриманий результат до завершення програми. Отже, щоб не заплутатися як з рекурсією, так і з належним представленням рядків, я вирішив подати 2-рядкову функцію, де завданням верхньої лінії є просто викликати нижню. Наслідок? Величезна витрата 2 дорогоцінних і цінних байтів. У захисті Джеллі (і Денніса, як і всіх інших учасників) захист,

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