Напишіть найкоротшу програму для обчислення висоти двійкового дерева


18

Висота двійкового дерева - це відстань від кореневого вузла до дочірнього вузла, що знаходиться найдалі від кореня.

Нижче наведено приклад:

           2 <-- root: Height 1
          / \
         7   5 <-- Height 2
        / \   \
       2   6   9 <-- Height 3
          / \  /
         5  11 4 <-- Height 4 

Висота двійкового дерева: 4

Визначення бінарного дерева

Дерево - це об'єкт, який містить підписане ціле значення та два інших дерева або покажчики на них.

Структура бінарної структури дерева виглядає приблизно так:

typedef struct tree
{
  struct tree * l;

  struct tree * r;

  int v;

} tree;

Змагання:

Вхідні дані

Корінь двійкового дерева

Вихід

Число, яке представляє висоту двійкового дерева

Припускаючи, що вам подано корінь двійкового дерева як вхідний, напишіть найкоротшу програму, яка обчислює висоту бінарного дерева та повертає висоту. Виграє програма з найменшою кількістю байтів (облік пробілів).


4
Що беруть мови без покажчиків?
Джонатан Аллан

4
... але тоді мій об’єкт дерева міг просто мати властивість, скажімо h. Можливо, краще визначити конкретну структуру, складену лише із списків, для цієї задачі.
Джонатан Аллан

11
@ T.Salim. В майбутньому, будь ласка, спершу подумайте про публікацію у пісочниці .
wizzwizz4

1
Отже, чи є коректним поданням список довжиною 3, [root_value, left_node, right_node]де кожне з них, left_nodeа right_nodeтакож є бінарними деревами, прийнятні? Це буде тривіально на багатьох мовах, але може бути цікавим у деяких інших.
Джонатан Аллан

3
Чи можете ви відредагувати питання, щоб включити те, що є дійсною бінарною структурою? Можливо, таке визначення, як a tree is an object that contains a value and either two other trees or pointers to them. Також було б непоганим визначення, яке включає мови без об’єктів.
Джо Кінг

Відповіді:


11

Желе , 3 байти

ŒḊ’

Монадична посилання, що приймає список, що представляє дерево:, [root_value, left_tree, right_tree]де кожна з left_treeі right_treeє подібними структурами (порожніми, якщо потрібно), що дає висоту.

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

Як?

Досить тривіально в Jelly:

ŒḊ’ - Link: list, as described above
ŒḊ  - depth
  ’ - decremented (since leaves are `[value, [], []]`)

Джонатан Аллен, це цікава мова, якою ви користуєтесь. Як новачок, чи можете ви надати посилання або веб-сайт, який навчає людей, як користуватися Jelly?
Т. Салим

4
Клацніть посилання в заголовку - це мова для гольфу, розроблена Деннісом , одним із модераторів сайту.
Джонатан Аллан

2
Цікаво, наскільки суперечливим було б представити листок, як xзамість [x, [], []]...
Ерік Покірник

@EriktheOutgolfer Щоб відповідати питанням "покажчик" та "структура", я думаю, кожен вузол повинен мати однакову форму.
Джонатан Аллан

10

Python 2 ,  35  33 байт

Дякуємо Арнольду за те, що помітили нагляд і заощадили 4.

f=lambda a:a>[]and-~max(map(f,a))

Рекурсивна функція, що приймає список, що представляє дерево:, [root_value, left_tree, right_tree]де кожна з left_treeі right_treeє подібними структурами (порожніми, якщо потрібно), що повертає висоту.

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

Зверніть увагу, що []повернеться False, але в Python False==0.


Цій же людині дозволяється дати дві різні відповіді на одне і те ж питання?
Т. Салим

6
Так, звичайно, гольф - це змагання на мовному рівні. Навіть другий запис тією ж мовою іноді прийнятний, якщо підхід дуже різний.
Джонатан Аллан

@Arnauld Вгадайте так (я припускав, що нецілі числа можуть бути присутніми чомусь)
Джонатан Аллан

6

Haskell, 33 байти

h L=0 
h(N l r _)=1+max(h l)(h r)

Використання користувацького типу дерева data T = L | N T T Int, що є еквівалентом Haskell структури C, заданої в виклику.

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


6

Perl 6 , 25 байт

{($_,{.[*;*]}...*eqv*)-2}

Введення - це 3-елементний список (l, r, v). Порожнє дерево - це порожній список.

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

Пояснення

{                       }  # Anonymous block
    ,        ...  # Sequence constructor
  $_  # Start with input
     {.[*;*]}  # Compute next element by flattening one level
               # Sadly *[*;*] doesn't work for some reason
                *eqv*  # Until elements doesn't change
 (                   )-2  # Size of sequence minus 2

Старий розчин, 30 байт

{+$_&&1+max map &?BLOCK,.[^2]}

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


&?BLOCKТрюк цікаво , але це кілька байт коротше , щоб призначити блок $!
Джо Кінг

@JoKing Я не знаю. Зберігання вирішення проблеми в мінливій глобальній схожій $!чи $/на мене схожій на обман.
nwellnhof

(Ab), використовуючи змінні типу $! і $ / є досить стандартною практикою для гольфу P6.
user0721090601

6

05AB1E , 11 7 5 байт

Δ€`}N

-4 байти завдяки @ExpiredData .
-2 байти завдяки @Grimy .

Формат введення схожий на відповідь Jelly: список, що представляє дерево:, [root_value, left_tree, right_tree]де кожне left_treeі right_treeє подібними структурами (необов'язково порожніми). Тобто [2,[7,[2,[],[]],[6,[5,[],[]],[11,[],[]]]],[5,[],[9,[4,[],[]],[]]]]являє собою дерево з опису завдання.

Спробуйте в Інтернеті або перевірте ще кілька тестових випадків .

Пояснення:

Δ     # Loop until the (implicit) input-list no longer changes:
  €`  #  Flatten the list one level
}N    # After the loop: push the 0-based index of the loop we just finished
      # (which is output implicitly as result)

Зауважте, що хоча 05AB1E заснований на 0, цикл змін Δспричиняє правильність вихідного індексу, тому що він потребує додаткової ітерації, щоб перевірити, чи він більше не змінюється.



@ExpiredData Ну, звичайно .. Дякую! :)
Kevin Cruijssen


@Grimy Я думав, що використання індексу поза циклом працювало лише у застарілому коді ..: S Дякую!
Кевін Кройсейсен

5

JavaScript (ES6),  35  33 байт

Структура вводу: [[left_node], [right_node], value]

f=([a,b])=>a?1+f(f(a)>f(b)?a:b):0

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

Прокоментував

f =                       // f is a recursive function taking
([a, b]) =>               // a node of the tree split into
                          // a[] = left child, b[] = right child (the value is ignored)
  a ?                     // if a[] is defined:
    1 +                   //   increment the final result for this branch
    f(                    //   and add:
      f(a) > f(b) ? a : b //     f(a) if f(a) > f(b) or f(b) otherwise
    )                     //
  :                       // else:
    0                     //   stop recursion and return 0

Схоже, ви можете зберегти байт за допомогою a&&-~.
Кошлатий

1
@Shaggy Це призведе до порівняння з невизначеним .
Арнольд

4

C, 43 байти

h(T*r){r=r?1+(int)fmax(h(r->l),h(r->r)):0;}

Структура бінарного дерева така:

typedef struct tree
{
  struct tree * l;

  struct tree * r;

  int v;

} tree;

2
55 байт Спробуйте в Інтернеті! Деякі химерні фокуси для гольфу є тут!
ErikF

1
@ErikF Або 45 байт
Арнольд


3
Якщо ваше подання покладається на прапори, чи можете ви додати їх у заголовок подання?
Джо Кінг

1
Будівля на @nwellnhof 42 байти
roofcat

4

JavaScript (Node.js) , 32 байти

f=a=>/,,/.test(a)&&f(a.flat())+1

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

Використання назви flatзамість flattenабо smooshє чудовою ідеєю для коду гольфу.

Використання []для нульового вузла на дереві та [left, right, value]для вузлів. valueось ціле число.



3

Haskell, 28 байт

Використовуючи таке визначення даних:

data T a = (:&) a [T a]

Висота:

h(_:&x)=foldr(max.succ.h)0 x

2

Схема, 72 байти

(define(f h)(if(null? h)0(+ 1(max(f(car(cdr h)))(f(car(cdr(cdr h))))))))

Більш читана версія:

(define (f h)
   (if (null? h)
      0
      (+ 1 
         (max
             (f (car (cdr h)))
             (f (car (cdr (cdr h))))
         )
      )
   )
)

Використовуючи списки форми (дані, зліва, справа) для зображення дерева. Напр

   1
  / \
  2  3
 /\
 4 5

is represented as: (1 (2 (4 () ()) (5 () ())) (3 () ())

(1
   (2
      (4 () ())
```   (5 () ())
   (3 () ())
)

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


2

R , 51 байт

function(L){while(is.list(L<-unlist(L,F)))T=T+1;+T}

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

  • Введення: вкладений список у форматі:list(ROOT_ELEMENT, LEFT_TREE, RIGHT_TREE)

  • Алгоритм: Ітеративно вирівнюється дерево на один рівень, поки воно не стає плоским вектором: кількість ітерацій відповідає максимальній глибині.

Натхненний @KevinCruijssen


Рекурсивна альтернатива:

R , 64 байти

`~`=function(L,d=0)'if'(is.list(L),max(L[[2]]~d+1,L[[3]]~d+1),d)

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

Перевизначає функцію / оператора '~' що дозволяє їй обчислити максимальну глибину дерева, що зберігається в структурі списку.

Структура списку дерева складається у форматі: list(ROOT_ELEMENT, LEFT_TREE, RIGHT_TREE)

  • -2 завдяки @Giuseppe

для чого ви використовуєте, d=1а потім d-1в кінці? Не могли ви почати 0?
Джузеппе

Крім того, я переключився >на ~ тут , так що тестові приклади легше ввести
Giuseppe

@Giuseppe: звичайно ... я пропускав очевидне 🤦‍♂️
digEmAll


1

K (нг / к) , 4 байти

Рішення:

#,/\

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

Пояснення:

Я думаю, що я, можливо, пропустив справу.

Представляючи дерево як список 3-х елементів (батьківський вузол; лівий-дочір; правий-дитина), приклад можна представити як

(2;
  (7;
    (,2);
    (6;
      (,5);
      (,11)
    )
  );
  (5;
    ();
    (9;
      (,4);
      ()
    )
  )
)

або: (2;(7;(,2);(6;(,5);(,11)));(5;();(9;(,4);()))).

Тож рішення полягає в ітераційному вирівнюванні та підрахунку ітерацій:

#,/\ / the solution
   \ / iterate
 ,/  / flatten
#    / count

0

Вугілля деревне , 29 байт

⊞θ⁰⊞υθFυ«≔⊕⊟ιθFΦι∧κλ⊞υ⊞Oκθ»Iθ

Спробуйте в Інтернеті! Посилання на багатослівну версію коду. Тимчасово модифікує дерево під час обробки. Пояснення:

⊞θ⁰

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

⊞υθ

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

Fυ«

Виконайте пошук по дереву в ширину.

≔⊕⊟ιθ

Отримайте глибину цього вузла.

FΦι∧κλ

Петля над будь-якими дочірніми вузлами.

⊞υ⊞Oκθ

Розкажіть дитині про вузол глибини його батьків і натисніть на список усіх вузлів.

»Iθ

Після проходження всіх вузлів надрукуйте глибину останнього вузла. Оскільки об’їзд був першим вшир, це буде висота дерева.


0

Стакс , 5 байт

▐▌µ╡⌂

Запустіть і налагодіть його

Stax не має ні вказівників, ні нульових значень, тому я представляю вхідні дані [2,[7,[2,[],[]],[6,[5,[],[]],[11,[],[]]]],[5,[],[9,[4,[],[]],[]]]] . Можливо, це несправедлива перевага, але це було найближче, що я міг отримати.

Розпакований, нерозроблений та коментований код виглядає приблизно так.

        The input starts on top of the input stack
Z       Tuck a zero underneath the top value in the stack.  Both values end up on the main stack.
D       Drop the first element from array
F       For each remaining element (the leaves) run the rest of the program
  G^    Recursively call the entire program, then increment
  T     Get maximum of the two numbers now ow the stack

Виконати цей



0

Юлія, 27 байт

f(t)=t≢()&&maximum(f,t.c)+1

З такою структурою, що представляє двійкове дерево:

struct Tree
    c::NTuple{2,Union{Tree,Tuple{}}}
    v::Int
end

cявляє собою кортеж, що представляє лівий і правий вузли, і порожній кортеж ()використовується для сигналізації про відсутність вузла.


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