Stolperte über diese alte Frage, während ich nach etwas anderem suchte. Ich stelle fest, dass Sie nie eine vollständige Antwort erhalten haben.
Um dieses Problem zu lösen, schreiben Sie zunächst eine Spezifikation für die Funktion, die Sie schreiben möchten.
Spezifikation: Ein wohlgeformter Binärbaum wird als "höhenausgeglichen" bezeichnet, wenn (1) er leer ist oder (2) seine linken und rechten untergeordneten Elemente höhenausgeglichen sind und die Höhe des linken Baums innerhalb von 1 liegt Höhe des rechten Baumes.
Nachdem Sie die Spezifikation haben, ist der Code trivial zu schreiben. Folgen Sie einfach der Spezifikation:
IsHeightBalanced(tree)
return (tree is empty) or
(IsHeightBalanced(tree.left) and
IsHeightBalanced(tree.right) and
abs(Height(tree.left) - Height(tree.right)) <= 1)
Die Übersetzung in die Programmiersprache Ihrer Wahl sollte trivial sein.
Bonusübung : Diese naive Codeskizze durchläuft den Baum bei der Berechnung der Höhen viel zu oft. Können Sie es effizienter machen?
Super Bonus Übung : Angenommen, der Baum ist massiv unausgeglichen. Eine Million Knoten tief auf der einen Seite und drei tief auf der anderen Seite. Gibt es ein Szenario, in dem dieser Algorithmus den Stapel sprengt? Können Sie die Implementierung so korrigieren, dass sie den Stapel niemals sprengt, selbst wenn ein massiv unausgeglichener Baum angegeben wird?
UPDATE : Donal Fellows weist in seiner Antwort darauf hin, dass es verschiedene Definitionen von "ausgewogen" gibt, die man wählen könnte. Zum Beispiel könnte man eine strengere Definition von "höhenausgeglichen" nehmen und verlangen, dass die Pfadlänge zum nächsten leeren Kind innerhalb eines der Pfade zum am weitesten leeren Kind liegt. Meine Definition ist weniger streng und lässt daher mehr Bäume zu.
Man kann auch weniger streng sein als meine Definition; Man könnte sagen, dass ein ausgeglichener Baum einer ist, bei dem sich die maximale Pfadlänge zu einem leeren Baum in jedem Zweig um nicht mehr als zwei oder drei oder eine andere Konstante unterscheidet. Oder dass die maximale Pfadlänge ein Bruchteil der minimalen Pfadlänge ist, wie ein halbes oder ein Viertel.
Normalerweise spielt es keine Rolle. Der Sinn eines Baumausgleichsalgorithmus besteht darin, sicherzustellen, dass Sie nicht in der Situation landen, in der Sie eine Million Knoten auf der einen und drei auf der anderen Seite haben. Donals Definition ist theoretisch in Ordnung, aber in der Praxis ist es ein Schmerz, einen Baumausgleichsalgorithmus zu entwickeln, der diese Strenge erfüllt. Die Leistungseinsparungen rechtfertigen normalerweise nicht die Implementierungskosten. Sie verbringen viel Zeit damit, unnötige Baumumlagerungen vorzunehmen, um ein Gleichgewicht zu erreichen, das in der Praxis kaum einen Unterschied macht. Wen kümmert es, wenn manchmal vierzig Äste benötigt werden, um zum entferntesten Blatt in einem unvollständig ausbalancierten Baum mit Millionen Knoten zu gelangen, wenn es in einem perfekt ausbalancierten Baum theoretisch nur zwanzig dauern könnte? Der Punkt ist, dass es nie eine Million braucht. Es ist normalerweise gut genug, von einem schlimmsten Fall von einer Million auf einen schlimmsten Fall von vierzig zu kommen. Sie müssen nicht bis zum optimalen Fall gehen.