VL-10: Binäre Suchbäume
(Datenstrukturen und Algorithmen, SS 2017)
Gerhard Woeginger
SS 2017, RWTH
DSAL/SS 2017 VL-10: Binäre Suchbäume 1/43
Organisatorisches
• Vorlesung: Gerhard Woeginger (Zimmer 4024 im E1) Sprechstunde: Mittwoch 11:15–12:00
• Übungen: Tim Hartmann, David Korzeniewski, Björn Tauer Email: dsal-i1@algo.rwth-aachen.de
• Webseite: http://algo.rwth-aachen.de/Lehre/SS17/DSA.php
• Nächste Vorlesung:
Dienstag, Mai 23, 16:15–17:45 Uhr, Aula 1
DSAL/SS 2017 VL-10: Binäre Suchbäume 2/43
Binäre Suchbäume
• Suchen
• Einfügen
• Löschen
• Rotationen
• AVL-Bäume
Motivation
Suchbäume unterstützen Operationen auf dynamischen Mengen, wie:
I
Suchen
I
Einfügen
I
Löschen
I
Abfragen (Nachfolger, oder Minimum, oder Maximum, etc) Die Basisoperationen auf binären Suchbäumen benötigen Laufzeit proportional zur Höhe des Baums:
I
Für vollständige binäre Bäume mit n Elementen liefert dies eine Laufzeit von Θ(log n) pro Basisoperation.
I
Für einen Baum, der einer linearen Kette mit n Elementen entspricht, ist dies aber Θ(n).
In der nächsten Vorlesung (VL-11) werden wir binäre Suchbäume
kennenlernen, deren Operationen immer Laufzeiten in O(log n) haben
Binäre Suchbäume (1)
Definition: Binärer Suchbaum
Ein binärer Suchbaum (BST) ist ein Binärbaum, der Elemente mit Schlüsseln enthält, wobei der Schlüssel jedes Knotens
I
mindestens so gross ist wie jeder Schlüssel im linken Teilbaum und
I
höchstens so gross ist wie jeder Schlüssel im rechten Teilbaum
63
2 5
7 9
Zwei binäre Suchbäume, die jeweils die sechs Schlüssel 2, 3, 5, 6, 7, 9 enthalten.
2 3
7 6 5
9
DSAL/SS 2017 VL-10: Binäre Suchbäume 5/43
Binäre Suchbäume (2)
Ein Knoten in einem binären Suchbaum besteht aus vier Feldern:
I
Einem Schlüssel = dem Wert des Knotens
I
einem (möglicherweise leeren) linken und einem (möglicherweise leeren) rechten Teilbaum, bzw. Zeiger darauf
I
einem Zeiger auf den Vater-/Mutterknoten (bei der Wurzel leer).
12
6 left
right
225 null
parent
Vater/Mutter von B und C
Linkes Kind von A
Rechtes Kind von A
Schlüssel
A
B
C
DSAL/SS 2017 VL-10: Binäre Suchbäume 6/43
Binäre Suchbäume (3)
Beispiel (Binärer Suchbaum in C/C++)
1 t y p e d e f s t r u c t _ n o d e * N o d e ; 2 s t r u c t _ n o d e {
3 int key ;
4 N o d e left , r i g h t ; 5 N o d e p a r e n t ;
6 // ... e v t l . e i g e n e D a t e n f e l d e r 7 };
8
9 s t r u c t _ t r e e { 10 N o d e r o o t ; 11 };
12
13 t y p e d e f s t r u c t _ t r e e * T r e e ;
Binäre Suchbäume (4)
Sortieren
Eine Inorder Traversierung eines binären Suchbaumes gibt alle Schlüssel im Suchbaum in sortierter Reihenfolge aus.
Zeitkomplexität
Da eine Inorder Traversierung eines Baumes mit n Knoten nur Θ(n) Zeit benötigt, erhalten wir einen Sortieralgorithmus mit Laufzeit Θ(n).
Dies setzt jedoch voraus, dass alle Daten bereits als ein BST
abgespeichert sind.
Suchen
DSAL/SS 2017 VL-10: Binäre Suchbäume 9/43
Suche nach Schlüssel k im BST
1 N o d e b s t S e a r c h ( N o d e root , int k ) { 2 w h i l e ( r o o t ) {
3 if ( k < r o o t . key ) { 4 r o o t = r o o t . l e f t ; } 5 e l s e if ( k > r o o t . key ) { 6 r o o t = r o o t . r i g h t ; } 7 e l s e { // k == r o o t . key 8 r e t u r n r o o t ; }
9 }
10 r e t u r n n u l l ; // n i c h t g e f u n d e n 11 }
Die Worst-Case Komplexität ist linear in der Höhe h des Baumes: Θ(h).
I
Für einen kettenartigen Baum mit n Knoten ergibt das Θ(n).
I
Ist der BST so balanziert wie möglich, erhält man Θ(log(n)).
Frage: Funktioniert dieses Suchverfahren auch bei Heaps?
DSAL/SS 2017 VL-10: Binäre Suchbäume 10/43
Beispiel: Suche nach Schlüssel k im BST (1)
15 5
3 12
10 6
14
16 20
17 31
Erfolgreiche Suche nach Schlüssel k = 10
Beispiel: Suche nach Schlüssel k im BST (2)
15 5
3 12
10 6
14
16 20
17 31
Erfolglose Suche nach Schlüssel k = 18
Einfügen
DSAL/SS 2017 VL-10: Binäre Suchbäume 13/43
Einfügen eines Knotens: Strategie
Einfügen
Man kann einen neuen Knoten mit Schlüssel k in den BST t einfügen, ohne die BST-Eigenschaft zu zerstören:
Suche einen geeigneten, freien Platz:
Wie bei der regulären Suche, ausser dass, selbst bei gefundenem Schlüssel, weiter abgestiegen wird, bis dass ein Knoten ohne entsprechendes Kind erreicht ist.
Hänge den neuen Knoten an:
Verbinde den neuen Knoten mit dem gefundenen Vaterknoten.
Komplexität: Θ(h), wegen der Suche.
DSAL/SS 2017 VL-10: Binäre Suchbäume 14/43
Beispiel: Einfügen von Schlüssel k = 18 in BST
Beispiel
15 5
3 12
10
6
14
16
20
17 31
15 5
3 12
10
6
14
16
20
17
18 31 bstIns(t, Node(18))
Einfügen eines Knotens: Algorithmus
1 v o i d b s t I n s ( T r e e t , N o d e n o d e ) { // F u e g e n o d e in t ein 2 // S u c h e f r e i e n P l a t z
3 N o d e r o o t = t . root , p a r e n t = n u l l ; 4 w h i l e ( r o o t ) {
5 p a r e n t = r o o t ;
6 if ( n o d e . key < r o o t . key ) { 7 r o o t = r o o t . l e f t ;
8 } e l s e {
9 r o o t = r o o t . r i g h t ;
10 }
11 } // E i n f u e g e n
12 n o d e . p a r e n t = p a r e n t ;
13 if (! p a r e n t ) { // t war l e e r = > n e u e W u r z e l 14 t . r o o t = n o d e ;
15 } e l s e if ( n o d e . key < p a r e n t . key ) { // r i c h t i g e S e i t e 16 p a r e n t . l e f t = n o d e ;
17 } e l s e {
18 p a r e n t . r i g h t = n o d e ;
19 }
20 }
Abfragen
DSAL/SS 2017 VL-10: Binäre Suchbäume 17/43
Abfragen im BST: Minimum
Problem
Wir suchen den Knoten mit dem kleinsten Schlüssel im durch
rootfestgelegten Baum oder Teilbaum.
Lösung
1 N o d e b s t M i n ( N o d e r o o t ) { // r o o t != n u l l 2 w h i l e ( r o o t . l e f t ) {
3 r o o t = r o o t . l e f t ;
4 }
5 r e t u r n r o o t ; 6 }
I
Komplexität: Θ(h) bei Baumhöhe h.
I
Das Maximum kann analog gefunden werden.
DSAL/SS 2017 VL-10: Binäre Suchbäume 18/43
Abfragen im BST: Nachfolger (1)
Problem
Wir suchen den Nachfolger-Knoten von
node, also den bei Inorder-Traversierung als nächstes zu besuchenden Knoten.
Der Schlüssel des Nachfolgers ist mindestens so gross wie
node.key.
Lösung
Der rechte Teilbaum existiert:
Nachfolger ist kleinster Knoten im rechten Teilbaum.
Andernfalls:
Nachfolger ist nächster Vorfahre, dessen linker Teilbaum
nodeenthält.
15 5
3 12
10 6
14 16
20 17 31
node
I
Komplexität: Θ(h) bei Baumhöhe h.
I
Der Vorgänger kann analog gefunden werden.
Abfragen im BST: Nachfolger (1)
Problem
Wir suchen den Nachfolger-Knoten von
node, also den bei Inorder-Traversierung als nächstes zu besuchenden Knoten.
Der Schlüssel des Nachfolgers ist mindestens so gross wie
node.key.
Lösung
Der rechte Teilbaum existiert:
Nachfolger ist kleinster Knoten im rechten Teilbaum.
Andernfalls:
Nachfolger ist nächster Vorfahre, dessen linker Teilbaum
nodeenthält.
15 5
3 12
10 6
14 16
20 17 31
node
I
Komplexität: Θ(h) bei Baumhöhe h.
I
Der Vorgänger kann analog gefunden werden.
Abfragen im BST: Nachfolger (2)
Der rechte Teilbaum existiert:
Nachfolger ist kleinster Knoten im rechten Teilbaum.
Andernfalls:
Nachfolger ist nächster Vorfahre, dessen linker Teilbaum
nodeenthält.
1 N o d e b s t S u c c ( N o d e n o d e ) { // n o d e != n u l l 2 if ( n o d e . r i g h t ) {
3 r e t u r n b s t M i n ( n o d e . r i g h t ) ;
4 }
5 // Ab b ru ch , w e n n n o d e n i c h t m e h r r e c h t e s K i n d 6 // o d e r w e n n n o d e . p a r e n t l e e r
7 w h i l e ( n o d e . p a r e n t && n o d e . p a r e n t . r i g h t == n o d e ) { 8 n o d e = n o d e . p a r e n t ;
9 }
10 r e t u r n n o d e . p a r e n t ; 11 }
DSAL/SS 2017 VL-10: Binäre Suchbäume 20/43
Ersetzen & Austauschen
DSAL/SS 2017 VL-10: Binäre Suchbäume 21/43
Ersetzen von Teilbäumen im BST
1 // E r s e t z t im B a u m t den T e i l b a u m old d u r c h 2 // den T e i l b a u m n o d e ( o h n e S o r t i e r u n g !)
3 v o i d b s t R e p l a c e ( T r e e t , N o d e old , N o d e n o d e ) { 4 if ( n o d e ) { // e r l a u b e n o d e == n u l l !
5 n o d e . p a r e n t = old . p a r e n t ;
6 }
7 if (! old . p a r e n t ) { // war die W u r z e l 8 t . r o o t = n o d e ;
9 } e l s e if ( old == old . p a r e n t . l e f t ) { 10 // war l i n k e s K i n d
11 old . p a r e n t . l e f t = n o d e ; 12 } e l s e { // r e c h t e s K i n d 13 old . p a r e n t . r i g h t = n o d e ;
14 }
15 }
Das Ersetzen eines Teilbaums hat Zeitkomplexität Θ(1).
Austauschen von Knoten im BST
1 // T a u s c h t den K n o t e n old g e g e n n o d e aus ; 2 // die K i n d e r von old s i n d w e i t e r h i n im BST ! 3 v o i d b s t S w a p ( T r e e t , N o d e old , N o d e n o d e ) { 4 // u e b e r n i m m l i n k e n T e i l b a u m
5 n o d e . l e f t = old . l e f t ; // a u c h m o e g l i c h : s w a p () 6 if ( n o d e . l e f t ) {
7 n o d e . l e f t . p a r e n t = n o d e ;
8 }
9 // r e c h t e n T e i l b a u m 10 n o d e . r i g h t = old . r i g h t ; 11 if ( n o d e . r i g h t ) {
12 n o d e . r i g h t . p a r e n t = n o d e ;
13 }
14 // f u e g e den K n o t e n ein 15 b s t R e p l a c e ( t , old , n o d e ) ; 16 }
Das Austauschen eines Knotens hat Zeitkomplexität Θ(1).
Löschen
DSAL/SS 2017 VL-10: Binäre Suchbäume 24/43
Löschen im BST: Die beiden einfachen Fälle
5
3 12
16 20 17 31 6
15
10 14
5
3 12
16 20 17 31 6
15
10
5
3 20
17 31 6
15
10 14 12
16 5
3 20
17 31 6
15
10 14 12
DSAL/SS 2017 VL-10: Binäre Suchbäume 25/43
Löschen im BST: Der aufwändigere Fall
3 20
17 31
6
15
10 14 12
16 5
3 20
17 31
6 15
10 14 12
16 5
3 20
17 31 6
15
10 14 12
16
Löschen im BST: Strategie
Löschen
Um Knoten
nodeaus dem BST zu löschen, verfahren wir folgendermassen:
Fall 1:
nodehat keine Kinder:
Ersetze im Vaterknoten von
nodeden Zeiger auf
nodedurch
nullFall 2:
nodehat ein Kind:
Wir schneiden
nodeaus, indem wir den Vater und das Kind direkt miteinander verbinden (den Teilbaum ersetzen).
Fall 3:
nodehat zwei Kinder:
Wir finden den Nachfolger von
node, entfernen ihn aus seiner ursprünglichen Position und tauschen
nodegegen den Nachfolger.
I
Es tritt nur der erste Fall (
bstMin(node.right)) aus
bstSuccauf.
I
Der gesuchte Nachfolger hat kein linkes Kind.
Löschen im BST: Algorithmus
1 // E n t f e r n t n o d e aus dem B a u m .
2 // D a n a c h k a n n n o d e ggf . aus S p e i c h e r e n t f e r n t w e r d e n 3 v o i d b s t D e l ( T r e e t , N o d e n o d e ) {
4 if ( n o d e . l e f t && n o d e . r i g h t ) { // z w e i K i n d e r 5 N o d e tmp = b s t M i n ( n o d e . r i g h t ) ;
6 b s t D e l ( t , tmp ) ; // h o c h s t e n s ein Kind , r e c h t s 7 b s t S w a p ( t , node , tmp ) ;
8 } e l s e if ( n o d e . l e f t ) { // ein Kind , l i n k s 9 b s t R e p l a c e ( t , node , n o d e . l e f t ) ;
10 } e l s e { // ein o d e r k e i n K i n d ( n o d e . r i g h t == n u l l ) 11 b s t R e p l a c e ( t , node , n o d e . r i g h t ) ;
12 }
13 }
DSAL/SS 2017 VL-10: Binäre Suchbäume 28/43
Komplexität der Operationen auf BSTs
Operation Zeit
bstSearch
Θ(h)
bstSucc
Θ(h)
bstMin
Θ(h)
bstIns
Θ(h)
bstDel
Θ(h)
I
Alle Operationen sind linear in der Höhe h des BSTs
I
Die Höhe ist log
2n, falls der Baum nicht allzu unbalanziert ist
I
Ein binärer Baum kann mittels Rotationen wieder balanziert werden
DSAL/SS 2017 VL-10: Binäre Suchbäume 29/43
Zufällig erzeugte binäre Suchbäume
Zufällig erzeugter BST
Ein zufällig erzeugter BST mit n Elementen ist ein BST, der durch das Einfügen von n Schlüsseln in zufälliger Reihenfolge in einen anfangs leeren Baum entsteht.
Annahme: Jede der n! möglichen Einfügungsordnungen hat gleiche Wahrscheinlichkeit.
Theorem (ohne Beweis)
Die erwartete Höhe eines zufällig erzeugten BSTs mit n Elementen beträgt O(log n).
Fazit: Im Schnitt verhält sich ein binärer Suchbaum wie ein (fast) balanzierter Suchbaum.
Rotationen & AVL-Bäume
leftRotate: Konzept und Beispiel
A
B C A B
C 1
2 1
2
leftRotate(1)
rightRotate(2)
Beispiel
leftRotate(5)
3 12
10 14 13
14 12 5 3 10 15
20 17 31
15
17 20
31 5
13
DSAL/SS 2017 VL-10: Binäre Suchbäume 32/43
Rotationen: Eigenschaften und Komplexität
A
B C A B
C 1
2 1
2
leftRotate(1)
rightRotate(2)
Lemma
I
Ein rotierter BST ist wieder ein BST
I
Die Inorder-Traversierung beider Bäume bleibt unverändert
Zeitkomplexität
Die Zeitkomplexität für Links- oder Rechtsrotieren ist in Θ(1).
DSAL/SS 2017 VL-10: Binäre Suchbäume 33/43
leftRotate: Algorithmus
1 v o i d l e f t R o t a t e ( T r e e t , N o d e n o d e 1 ) { 2 // v o e l l i g a n a l o g : r i g h t R o t a t e () 3 N o d e n o d e 2 = n o d e 1 . r i g h t ; 4 // B a u m B v e r s c h i e b e n 5 n o d e 1 . r i g h t = n o d e 2 . l e f t ; 6 if ( n o d e 1 . r i g h t ) {
7 n o d e 1 . r i g h t . p a r e n t = n o d e 1 ;
8 }
9 // n o d e 2 w i e d e r e i n h a e n g e n 10 n o d e 2 . p a r e n t = n o d e 1 . p a r e n t ;
11 if (! n o d e 1 . p a r e n t ) { // n o d e 1 war die W u r z e l 12 t . r o o t = n o d e 2 ;
13 } e l s e if ( n o d e 1 == n o d e 1 . p a r e n t . l e f t ) { 14 n o d e 2 . p a r e n t . l e f t = n o d e 2 ;
15 } e l s e { // war r e c h t e s K i n d 16 n o d e 2 . p a r e n t . r i g h t = n o d e 2 ;
17 }
18 // n o d e 1 e i n h a e n g e n 19 n o d e 2 . l e f t = n o d e 1 ; 20 n o d e 1 . p a r e n t = n o d e 2 ; 21 }
AVL-Bäume
Definition: AVL-Baum
I
Ein AVL-Baum ist balanzierter BST, bei dem sich für jeden Knoten die Höhen der beiden Teilbäume um höchstens 1 unterscheiden.
I
Bei AVL-Bäumen wird Höhe der Teilbäume der Knoten balanziert.
I
Dazu wird (in einem zusätzlichem Datenfeld) in jedem Knoten über die Höhe des Unterbaums Buch geführt.
I
Nach jeder Operation wird die Balance wiederhergestellt. Dies ist in Θ(h) möglich!
I
Dadurch bleibt stets h ∈ Θ(log n), und Θ(log n) kann für alle Operationen auf dem BST garantiert werden.
• Georgy Adelson-Velsky (1922-2014): Sowjetisch/Israelischer Mathematiker
• Evgenii Landis (1921-1997): Sowjetischer Mathematiker
• “An algorithm for the organization of information”, Proceedings of the USSR Academy of Sciences, 1962
AVL-Bäume: Balanzieren nach Einfügen (1)
Jeder AVL-Baum ist (höhen)balanziert. Für alle Knoten x gilt:
| rechte Teilbaumhöhe − linke Teilbaumhöhe
| {z }
balance(x)
| ≤ 1
Falls wir einen neuen Knoten in den Baum einfügen, so kann der Baum dadurch unbalanziert werden.
Die Balance wird dann durch Rotation wieder hergestellt.
I
Einfachrotation, wenn die tieferen Blätter “außen” liegen.
I
Doppelrotation, wenn die tieferen Blätter “innen” liegen.
DSAL/SS 2017 VL-10: Binäre Suchbäume 36/43
AVL-Bäume: Balanzieren nach Einfügen (2)
SeiAder tiefste unbalanzierte Knoten auf dem Pfad von Wurzel zum neu eingefügten Knoten(unbalanziert:linke Teilbaumhöhe−rechte Teilbaumhöhe=±2)
A
Rechter Teilbaum ist größer:
Zwei Fälle RR und RL
A B
RR: Linksrotation aufA:
B A
A B
RL: Zwei analoge Fälle:
A B C
Rechtsrotation aufB:
A C
B
Linksrotation aufA:
A C
B
A B C
Rechtsrotation aufB:
A C
B
Linksrotation aufA:
A C
B
DSAL/SS 2017 VL-10: Binäre Suchbäume 37/43
AVL-Bäume: Balanzieren nach Einfügen (3)
SeiAder tiefste unbalanzierte Knoten auf dem Pfad von Wurzel zum neu eingefügten Knoten(unbalanziert:linke Teilbaumhöhe−rechte Teilbaumhöhe=±2)
A
Linker Teilbaum ist größer:
Zwei Fälle LL und LR
A B
LL: Rechtsrotation aufA:
A B
A B
LR: Zwei analoge Fälle:
A B
C
Linksrotation aufB:
A C B
Rechtsrotation aufA:
A C B
A B
C
Linksrotation aufB:
A C B
Rechtsrotation aufA:
A C B
AVL-Bäume: Balanzieren nach Einfügen (4a)
1 v o i d A V L I n s ( T r e e t , N o d e n o d e ) { 2 b s t I n s ( t , n o d e ) ;
3 // N o d e d e e p e s t U n b a l a n c e d N o d e ( T r e e t , N o d e n o d e ) 4 // g i b t n u l l z u r u e c k w e n n t b a l a n z i e r t ist
5 // und den t i e f s t e n u n b a l a n z i e r t e n K n o t e n in t s o n s t 6 // ( der P a r a m e t e r n o d e w i r d zur e f f i z i e n t e n
7 // I m p l e m e n t i e r u n g v e r w e n d e t )
8 N o d e A = d e e p e s t U n b a l a n c e d N o d e ( t , n o d e ) ; 9 if ( A != n u l l ) b a l a n c e ( t , A ) ;
10 }
AVL-Bäume: Balanzieren nach Einfügen (4b)
1 v o i d b a l a n c e ( T r e e t , N o d e A ) {
2 // A ist t i e f s t e r u n b a l a n z i e r t e r K n o t e n in t 3 if ( h e i g h t ( A . l e f t ) > h e i g h t ( A . r i g h t ) ) {
4 if ( h e i g h t ( A . l e f t . l e f t ) >= h e i g h t ( A . l e f t . r i g h t ) ) {// LL 5 r i g h t R o t a t e ( t , A ) ;
6 } e l s e { // LR
7 l e f t R o t a t e ( A . l e f t ) ; r i g h t R o t a t e ( A ) ;
8 }
9 } e l s e {
10 if ( h e i g h t ( A . r i g h t . r i g h t ) >= h e i g h t ( A . r i g h t . l e f t ) ) {
11 // RR
12 l e f t R o t a t e ( t , A ) ;
13 } e l s e { // RL
14 r i g h t R o t a t e ( A . r i g h t ) ; l e f t R o t a t e ( A ) ;
15 }
16 }
17 }
DSAL/SS 2017 VL-10: Binäre Suchbäume 40/43
AVL-Bäume: Balanzieren nach Löschen
Baumhöhe von A nach Rotation
= Baumhöhe vor Einfügen des neuen Knotens
Ergo: Nach Balanzieren von A ist der gesamte Baum wieder balanziert.
Auch das Löschen eines Knotens kann Unbalanziertheit verursachen:
I
Die Balanzierung des tiefsten unbalanzierten Knotens kann auf analoge Weise wie beim Einfügen erreicht werden.
I
Aber: der Teilbaum hat danach nicht mehr die gleiche Höhe wie vor dem Löschen (die Höhe ist um 1 kleiner geworden)!
I
Im schlimmsten Fall müssen dann alle unbalanzierten Knoten einzeln balanziert werden.
I
Da aber (1) die Balanzierung eines Knotens nur konstanten Aufwand erfordert und es (2) nur O(log n) unbalanzierte Knoten geben kann, ist der Gesamtaufwand immer noch logarithmisch.
DSAL/SS 2017 VL-10: Binäre Suchbäume 41/43
AVL-Bäume: Balanzieren nach Löschen
1 v o i d A V L D e l ( T r e e t , N o d e n o d e ) { 2 b s t D e l ( t , n o d e ) ;
3 // N o d e d e e p e s t U n b a l a n c e d N o d e ( T r e e t , N o d e n o d e ) 4 // g i b t n u l l z u r u e c k w e n n t b a l a n z i e r t ist
5 // und den t i e f s t e n u n b a l a n z i e r t e n K n o t e n in t s o n s t 6 //( der P a r a m e t e r n o d e w i r d zur e f f i z i e n t e n
7 // I m p l e m e n t i e r u n g v e r w e n d e t )
8 N o d e A = d e e p e s t U n b a l a n c e d N o d e ( t , n o d e ) ; 9 w h i l e ( A != n u l l ) {
10 // b o o l b a l a n c e d ( T r e e t , N o d e A )
11 // g i b t t r u e z u r u e c k w e n n A b a l a n z i e r t ist in t 12 // und f a l s e s o n s t
13 if (! b a l a n c e d ( t , A ) ) { 14 b a l a n c e ( t , A ) ; 15 A = A . p a r e n t . p a r e n t ;
16 } e l s e {
17 A = A . p a r e n t ;
18 }
19 }
20 }