Натрапив на це старе питання, шукаючи щось інше. Я помічаю, що ви ніколи не отримували повної відповіді.
Спосіб вирішення цієї проблеми - почати з написання специфікації для функції, яку ви намагаєтеся написати.
Специфікація: Добре сформоване бінарне дерево називається "зрівноваженим по висоті", якщо (1) воно порожнє, або (2) його ліві та праві діти дорівнюють по висоті і висота лівого дерева знаходиться в межах 1 висота правильного дерева.
Тепер, коли у вас є специфікація, код потрібно тривіально записати. Просто дотримуйтесь специфікації:
IsHeightBalanced(tree)
return (tree is empty) or
(IsHeightBalanced(tree.left) and
IsHeightBalanced(tree.right) and
abs(Height(tree.left) - Height(tree.right)) <= 1)
Переклад цього на мову програмування на ваш вибір повинен бути тривіальним.
Бонусні вправи : цей наївний ескіз коду занадто багато разів обходить дерево, обчислюючи висоти. Чи можете ви зробити це більш ефективним?
Супер бонусна вправа : припустимо, дерево масово врівноважене. Мовляв, мільйон вузлів глибоко з одного боку і три глибокі з іншого. Чи існує сценарій, при якому цей алгоритм видуває стек? Чи можете ви зафіксувати реалізацію таким чином, щоб вона ніколи не забивала стек, навіть коли деревце масово не врівноважене?
ОНОВЛЕННЯ : Доналісти стипендіати вказують у своїй відповіді, що існують різні визначення поняття "збалансований", який можна вибрати. Наприклад, можна взяти суворіше визначення «зрівноваженого по висоті» і вимагати, щоб довжина шляху до найближчої порожньої дитини була в межах одного зі шляху до найдальшої порожньої дитини. Моє визначення менш суворе, ніж це, і тому допускає більше дерев.
Можна також бути менш суворим, ніж моє визначення; можна сказати, що врівноважене дерево - це те, в якому максимальна довжина шляху до порожнього дерева на кожній гілці відрізняється не більше ніж на два, три, або якусь іншу константу. Або що максимальна довжина шляху - це якась частка мінімальної довжини шляху, як півтора чи чверть.
Зазвичай це не має значення. Суть будь-якого алгоритму балансування дерев полягає в тому, щоб ви не закінчилися в ситуації, коли у вас мільйон вузлів з одного боку і три з іншого. Визначення Доналя теоретично добре, але на практиці це біль, що створює алгоритм балансування дерев, який відповідає такому рівню суворості. Економія ефективності зазвичай не виправдовує витрат на впровадження. Ви витрачаєте багато часу, роблячи непотрібні перестановки дерев, щоб досягти рівня рівноваги, який на практиці мало значення. Кому байдуже, якщо іноді потрібно сорок гілок, щоб дістатися до найдальшого листя в мільйоні вузлів недосконало врівноваженого дерева, коли теоретично в ідеально збалансованому дереві воно може зайняти лише двадцять? Справа в тому, що це ніколи не займає мільйон. Перехід від найгіршого випадку від мільйона до гіршого за сорок - це зазвичай досить добре; вам не доведеться пройти весь шлях до оптимального випадку.