Algorithmen und Datenstrukturen 1 Fachhochschule Regensburg

Werbung
Algorithmen und Datenstrukturen
Fachhochschule Regensburg
Algorithmen und Datenstrukturen
AVL-Bäume 1
Übung 43_2
Algorithmen und Datenstrukturen
Name: ________________________
Lehrbeauftragter: Prof. Sauer
Vorname: _____________________
Abb. 1: Darstellung eines AVL-Baums mit Balancierungsangeben (Höhendifferenzen) 2
1. Einfügen von Knoten im AVL-Baum 3
Ein binärer Suchbaum hat die AVL-Eigenschaft, wenn sich in jedem Knoten sich die Höhen der beiden
Teilbäume höchstens um 1 unterscheiden. Diese Last („Balance“) muß in einem Knoten gespeichert
sein. Es genügt aber als Maß für die Unsymmetrie eine Höhendifferenz festzuhalten, die nur die Werte
–1 (linkslastig), 0 (gleichlastig) und +1 (rechtslastig) annehmen kann. Die AVL-Eigenschaft ist verletzt,
wenn diese Höhendifferenz +2 bzw. –2 ist. Der Knoten, der diesen Wert erhalten hat, ist der Knoten
„alpha“, dessen Unausgeglichenheit auf einen der folgenden 4 Fälle zurückzuführen ist:
1. Einfügen in den linken Teilbaum, der vom linken Nachkommen des Knoten „alpha“ bestimmt ist.
2. Einfügen in den rechten Teilbaum, der vom linken Nachkommen des Knoten „alpha“ bestimmt ist.
3. Einfügen in den linken Teilbaum, der vom rechten Nachkommen des Knoten „alpha“ bestimmt ist.
4. Einfügen in den rechten Teilbaum, der vom rechten Nachkommen des Knoten „alpha“ bestimmt ist
Fall 1 und Fall 4 bzw. Fall 2 und Fall 3 sind Spiegelbilder, zeigen also das gleiche Verhalten.
Fall1 kann durch einfache Rotation behandelt werden und ist leicht zu bestimmen, daß das Einfügen
„außerhalb“ (links – links bzw. rechts – rechts im Fall 4) stattfindet.
Fall 2 kann durch doppelte Rotation behandelt werden und ist ebenfalls leicht zu bestimmen, da das
Einfügen „innerhalb“ (links –rechts bzw. rechts – links) erfolgt.
Die einfache Rotation
Die folgende Darstellung beschreibt den Fall 1 vor und nach der Rotation:
1
Vgl. Skriptum 4.3.2, http://fbim.fh-regensburg.de/~saj39122/bruhi/index.html
vgl. AVLTreeTest.java, AVLTree.java,
3 vgl. Skriptum, 4.3.2
2
1
Algorithmen und Datenstrukturen
k2
k1
k1
k2
Z
Y
X
Y
Z
X
Die folgende Darstellung beschreibt Fall 4 vor und nach der Rotation :
k1
k2
k2
k1
X
Y
X
Y
Z
Z
Doppelrotation
Die einfache Rotation führt in den Fällen 2 und 3 nicht zum Erfolg.
Fall 2 muß durch eine Doppelrotation (links – rechts) behandelt werden.
k3
k2
k1
k1
k3
D
k2
B
A
A
B
C
2
C
D
Algorithmen und Datenstrukturen
Auch Fall 3 muß durch Doppelrotation behandelt werden
k1
k3
k2
k1
k2
A
k3
D
B
C
A
B
D
C
Implementierung 4
Zum Einfügen eines Knoten mit dem Datenwert „x“ in einen AVL-Baum, wird „x“ rekursiv in den
betoffenen Teilbaum eingesetzt. Falls die Höhe dieses Teilbaums sich nicht verändert, ist das
Einfügen beendet. Liegt Unausgeglichenheit vor, dann ist einfache oder doppelte Rotation (abhängig
von „x“ und den Daten des betroffenen Teilbaums) nötig.
AVL-Baumknoten
Er enthält für jeden Knoten eine Angabe zur Höhe(ndifferenz) 5 seiner Teilbäume.
// Baumknoten fuer AVL-Baeume
struct AvlNode
{
Comparable element;
AvlNode
*left;
AvlNode
*right;
int
height;
// Konstruktor
AvlNode( const Comparable & theElement, AvlNode *lt, AvlNode *rt,
int h = 0 )
: element( theElement ), left( lt ), right( rt ), height( h ) { }
};
Der AVL-Baum
Bei jedem Schritt ist festzustellen, ob die Höhe des Teilbaums, in dem ein Element eingefügt wurde,
zugenommen hat.
/* Rückgabe der Hoehe des Knotens t oder -1, wenn NULL */
int height( AvlNode *t ) const
{
return t == NULL ? -1 : t->height;
}
Die Methode „insert“ führt das Einfügen eines Baumknoten in den Avl-Baum aus:
/*
* Interne Methode zum Einfuegen eines Baumknoten in einen Teilbaum.
* x ist das einzufuegende Datenelement.
* t ist der jeweilige Wurzelknoten.
*/
void insert( const Comparable& x, AvlNode * & t )
{
4
5
pr43_2
vgl. Skriptum, 4.3.2
3
Algorithmen und Datenstrukturen
if( t == NULL )
t = new AvlNode( x, NULL, NULL );
else if( x < t->element )
{
insert( x, t->left );
if( height( t->left ) - height( t->right ) == 2 )
if( x < t->left->element )
rotateWithLeftChild( t );
else doubleWithLeftChild( t );
}
else if( t->element < x )
{
insert( x, t->right );
if( height( t->right ) - height( t->left ) == 2 )
if( t->right->element < x )
rotateWithRightChild( t );
else doubleWithRightChild( t );
}
else
; // Duplikat, ueber gehen
t->height = max( height( t->left ), height( t->right ) ) + 1;
}
Einfache Rotation
RotationMitLinksNachf dreht den Linken Teilbaum der folgenden Darstellung nach rechts.
k2
k1
k1
k2
Z
Y
X
Y
Z
X
/*
* Rotation Binaerbaumknoten mit linkem Nachfolger.
* Fuer AVL-Baeume ist dies eine einfache Rotation (Fall 1).
* Aktualisiert Angaben zur Hoehe, dann Rueckgabe der neuen Wurzel.
*/
void rotateWithLeftChild( AvlNode * & k2 )
{
AvlNode *k1 = k2->left;
k2->left = k1->right;
k1->right = k2;
k2->height = max( height( k2->left ), height( k2->right ) ) + 1;
k1->height = max( height( k1->left ), k2->height ) + 1;
k2 = k1;
}
/*
* Rotation Binaerbaumknoten mit rechtem Nachfolger.
* Fuer AVL-Baeume ist dies eine einfache Rotation (Fall 4).
* Aktualisiert Angaben zur Hoehe,, danach Rueckgabe der neuen Wurzel.
*/
4
Algorithmen und Datenstrukturen
void rotateWithRightChild( AvlNode * & k1 )
{
AvlNode *k2 = k1->right;
k1->right = k2->left;
k2->left = k1;
k1->height = max( height( k1->left ), height( k1->right ) ) + 1;
k2->height = max( height( k2->right ), k1->height ) + 1;
k1 = k2;
}
Doppelrotation
“doppelrotationMitLinksNachf” führt die folgende Umstellung der Baumknoten aus:
k3
k2
k1
k1
k3
D
k2
B
A
C
A
B
C
/*
* Doppelrotation der Binaerbaumknoten: : erster linker Nachfolgeknoten
* mit seinem rechten Nachfolger; danach Knoten k3 mit neuem linken
* Nachfolgerknoten.
* Fuer AVL-Baeume ist dies eine doppelte Rotation (Fall 2)
* Aktualisiert Angaben zur Hoehe,, danach Rueckgabe der neuen Wurzel.
*/
void doubleWithLeftChild( AvlNode * & k3 )
{
rotateWithRightChild( k3->left );
rotateWithLeftChild( k3 );
}
/*
* Doppelrotation der Binaerbaumknoten: : erster linker Nachfolgeknoten
* mit seinem rechten Nachfolger; danach Knoten k3 mit neuem linken
* Nachfolgerknoten.
* Fuer AVL-Baeume ist dies eine doppelte Rotation (Fall 2)
* Aktualisiert Angaben zur Hoehe,, danach Rueckgabe der neuen Wurzel.
*/
void doubleWithRightChild( AvlNode * & k1 )
{
rotateWithLeftChild( k1->right );
rotateWithRightChild( k1 );
}
5
D
Algorithmen und Datenstrukturen
2. Löschen von Knoten im AVL-Baum
Das Löschen eines Knotens (Schlüssel x) mit 2 Kindern kann auf das Löschen von Blatt-/Randknoten
zurückgeführt werden. Für innere Knoten gilt:
-
„x“ wird ersetzt durch den kleinsten Schlüssel y im rechten Teilbaum von x (bzw. größten
Schlüssel im linken Teilbaum).
Führt zur Änderung des Balancierungsfaktors für v (Höhe des linken Teilbaums von v hat sich
um 1 reduziert).
x
y
⇒
v
v
Bl
Bl
z
y
B ry
B ry
Br
Br
z
Bis auf Symmetrie treten nur 3 Fälle auf.
Fall 1:
0
v
h+1
1
h+1
Löschen in Bl
⇒
h
h
h-1
Bl
Bl
h
Br
Br
In diesem Fall pflanzt sich Höhenerniedrigung nicht fort, da in der Wurzel das AVL-Kriterium erfüllt
bleibt, d.h. kein Rebalancieren erforderlich.
Fall 2:
-1
h+1
0
h
Löschen in Bl
⇒
h
h-1
Bl
h-1
Br
Bl
Br
h-1
Die Höhenerniedrigung von Bl pflanzt sich hier zur Wurzel fort. Sie kann auf diesem Pfad eine
Rebalancierung auslösen.
6
Algorithmen und Datenstrukturen
Fall 3:
-1
h+1
-2
h+1
Löschen in Br
⇒
h
h-1
h
Br
Bl
h-2
Br
Bl
Für die Behandlung dieser Situation ist der linke Teilbaum Bl genauer zu betrachten. Dabei ergeben
sich 3 Unterfälle:
Fall 3a:
-2
x4
1
x2
h+1
h+1
⇒
0
x2
-1
x4
B5
h-2
h-1
B1
h-1
h-1
h-1
B3
0
x2
h
h-2
B5
h-2
B5
B3
B1
- Rechtsrotation führt zur Erfüllung des AVL-Kriteriums
- Teilbaum behält ursprüngliche Höhe
- Keine weiteren Rebalancierungen erforderlich
Fall 3b:
-2
x4
h+1
⇒
-1
x2
0
x4
B5
h-2
h-1
B1
h-1
h-2
B1
h-2
B3
B3
- Rechtsrotation reduziert Höhe des gesamten Teilbaum von h+1 nach h
- Höhenreduzierung pflanzt sich auf dem Pfad zur Wurzel hin fort und kann zu weiteren
Rebalancierungen führen.
7
Algorithmen und Datenstrukturen
-2 h+1
x6
+1
x2
0
x4
h
h
h-2
0
x2
B7
0
x4
0
x6
h-2
h-2
B1
B3
B5
B7
B1
h-2
h-2
B3
B5
- Doppelrotation
- ggf. fortgesetzte Rebalancierungen
Rebalancierungsschritte beim Löschen
1. Suche im Löschpfad nähesten Vater mit Balancierungsfaktor +/-2
2. Führe ggf. Rotation im gegenüberliegenden Teilbaum dieses Vaters auf. Im Gegensatz zum
Einfügevorgang kann hier eine Rotation wiederum auf dem Pfad zur Wurzel auslösen, da sie
in gewissen Fällen auf eine Höhenerniedrigung des transformierten Teilbaums führt. Die
Anzahl der Rebalancierungsschritte ist jedoch durch die Höhe h des Baums begrenzt.
3. Höhe von AVL-Bäumen
Balancierte Bäume werden als Kompromiß zwischen ausgeglichenen und natürlichen Suchbäumen
eingeführt, wobei „logarithmischer Suchaufwand“ im schlechtesten Fall gefordert wurde. Für die
h +1
− 1 . Daraus erhält man zur
maximale Anzahl von Knoten n gilt folgende Ungleichung: n ≤ 2
Abschätzung der Höhe: h ≤ 2 ⋅ log 2 n + 1 . Das bedeutet, dass die Höhe eines AVL-Baums von der
Wurzel bis zu einem beliebigen Knoten höchstens 2 ⋅ log 2 n + 1 ist
4. Komplexität von Opeartionen aujf AVL-Bäumen
- Komplexität für Einfügen und Löschen in binären Suchbäumen: O (h) .
-- im AVL- Baum gilt: h = O (log n)
-- Notwendige Rotationen sind in konstanter Zeit auszuführen
- Ausbalancieren nach Einfügen erfordert höchstens eine (einfache oder doppelte) Rotation.
Komplexität von insert: O (log n) + O (1) = O (log n)
- Ausbalancieren nach Löschen erfordert höchstens h (einfache und doppelte) Rotationen.
Komplexität von remove: O (log n) + O (log n) = O (log n)
- Einfügen und Löschen in AVL-Bäumen haben im schlechtesten Fall eine Komplexität von O(logn)
- Zusammenfassung: worst-case Komplexität O (log n) für Suchen, Einfügen und Löschen.
8
Herunterladen