Algorithmen und Datenstrukturen 1 Beispielblatt 2

Werbung
Beispielblatt 2
186.813 VU Algorithmen und Datenstrukturen 1 VU 6.0
25. September 2013
Aufgabe 1 Gegeben sei ein binärer Suchbaum mit Werten im Bereich von 1 bis 1001. In diesem
Baum wird nach der Zahl 363 gesucht. Überprüfen Sie für die angegebenen Folgen (a) bis (d),
ob die Elemente in der angegebenen Reihenfolge Werte von Knoten repräsentieren können, die
bei der Suche im binären Suchbaum travesiert wurden. Unterstützen Sie Ihre Argumentation
jeweils mit einer Skizze:
(a) h943, 217, 335, 712, 289, 397, 348, 363i
(b) h1001, 199, 935, 240, 936, 273, 363i
(c) h1000, 200, 898, 248, 889, 273, 361, 363i
(d) h2, 398, 388, 211, 276, 385, 379, 278, 363i
Lösung
(a) Von den ersten Zahlen 943 − 712 der Zahlenfolge ist es durchaus möglich, dass die
angegebene Folge Werte von Knoten in einem binären Suchbaum repräsentiert. Aber
der Knoten mit dem Wert 289 ist falsch eingeordnet, denn dieser müsste sich eigentlich in dem linken Teilbaum von Knoten 335 befinden. ⇒ Für die gesamte Zahlenfolge
h943, 217, 335, 712, 289, 397, 348, 363i ist es nicht möglich. (Der Wertebereich, den Knoten
im linken Teilbaum von 712 annehmen können ist zwischen 335 − 712)
943
217
335
712
289
(b) Von den ersten Zahlen 1001 − 240 der Zahlenfolge ist es durchaus möglich, dass die
angegebene Folge Werte von Knoten in einem binären Suchbaum repräsentiert. Aber
der Knoten mit dem Wert 936 ist falsch eingeordnet, denn dieser müsste sich eigentlich in dem rechten Teilbaum von Knoten 935 befinden. ⇒ Für die gesamte Zahlenfolge
h1001, 199, 935, 240, 936, 273, 363i ist es nicht möglich. (Der Wertebereich, den Knoten im
rechten Teilbaum von 240 annehmen können ist zwischen 240 − 935)
1001
199
935
240
936
(c) Ja, diese Travesierungsreihenfolge h1000, 200, 898, 248, 889, 273, 361, 363i ist durchaus
möglich, wenn es sich um einen binären Suchbaum handelt.
1000
200
898
248
889
273
361
363
(d) Ja, diese Travesierungsreihenfolge h2, 398, 388, 211, 276, 385, 379, 278, 363i ist durchaus
möglich, wenn es sich um einen binären Suchbaum handelt.
2
2
398
388
211
276
385
379
278
363
Listing 1: Check ob es sich um gültige Suchbäume handelt. (Für Klasse bin tree.h siehe Listing 3)
1
2
// This Project is written in C ++11 , so use following command to compile it :
// g ++ - ggdb - std = c ++11 -o bsp1 bsp1 . cpp
3
4
5
# include < iostream >
# include " bin_tree . h "
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int main (){
std :: cout << std :: endl << " Bsp 1. a " << std :: endl ;
{ // 1. a
{
bin_tree < int > t ;
static const int inserts [] = {943 ,217 ,335 ,712};
std :: vector < int > ins ( inserts , inserts + sizeof ( inserts ) / sizeof
for ( int i : ins ) {
t . insert ( i );
}
t . insert_manually (289 ,712 , true ); // insert the node 289 as leftchi
if ( t . c h e c k _ b i n a r y _ s e a r c h _ t r e e ()) {
std :: cout << " RICHTIG " << std :: endl ;
} else {
std :: cout << " FALSCH " << std :: endl ;
}
23
std :: cout << std :: endl <<t . to_string (3) << std :: endl ;
24
25
26
27
28
}
{
bin_tree < int > t ;
static const int inserts [] = {943 ,217 ,335 ,712 ,289};
3
std :: vector < int > ins ( inserts , inserts + sizeof ( inserts ) / sizeof
for ( int i : ins ) {
t . insert ( i );
}
std :: cout << std :: endl <<t . to_string (3) << std :: endl ;
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
}
}
std :: cout << std :: endl << " Bsp 1. b " << std :: endl ;
{ // 1. b
{
bin_tree < int > t ;
static const int inserts [] = {1001 , 199 , 935 , 240};
std :: vector < int > ins ( inserts , inserts + sizeof ( inserts ) / sizeof
for ( int i : ins ) {
t . insert ( i );
}
t . insert_manually (936 ,240 , false ); // insert the node 936 as rightc
if ( t . c h e c k _ b i n a r y _ s e a r c h _ t r e e ()) {
std :: cout << " RICHTIG " << std :: endl ;
} else {
std :: cout << " FALSCH " << std :: endl ;
}
51
std :: cout << std :: endl <<t . to_string (3) << std :: endl ;
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
}
{
bin_tree < int > t ;
static const int inserts [] = {1001 , 199 , 935 , 240 , 936};
std :: vector < int > ins ( inserts , inserts + sizeof ( inserts ) / sizeof
for ( int i : ins ) {
t . insert ( i );
}
std :: cout << std :: endl <<t . to_string (3) << std :: endl ;
}
}
std :: cout << std :: endl << " Bsp 1. c " << std :: endl ;
{ // 1. c
{
bin_tree < int > t ;
static const int inserts [] = {1000 , 200 , 898 , 248 , 889 , 273 , 361 ,
std :: vector < int > ins ( inserts , inserts + sizeof ( inserts ) / sizeof
for ( int i : ins ) {
t . insert ( i );
}
if ( t . c h e c k _ b i n a r y _ s e a r c h _ t r e e ()) {
std :: cout << " RICHTIG " << std :: endl ;
} else {
std :: cout << " FALSCH " << std :: endl ;
4
}
77
78
std :: cout << std :: endl <<t . to_string (3) << std :: endl ;
79
}
80
}
std :: cout << std :: endl << " Bsp 1. d " << std :: endl ;
{ // 1. d
{
bin_tree < int > t ;
static const int inserts [] = {2 , 398 , 388 , 211 , 276 , 385 , 379 , 27
std :: vector < int > ins ( inserts , inserts + sizeof ( inserts ) / sizeof
for ( int i : ins ) {
t . insert ( i );
}
if ( t . c h e c k _ b i n a r y _ s e a r c h _ t r e e ()) {
std :: cout << " RICHTIG " << std :: endl ;
} else {
std :: cout << " FALSCH " << std :: endl ;
}
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
std :: cout << std :: endl <<t . to_string (3) << std :: endl ;
97
}
98
}
99
100
return 0;
101
102
}
Aufgabe 2
Gegeben sei folgender AVL-Baum direkt nach dem Einfügen eines neuen Elements:
10
8
6
2
16
14
22
18
Ist die AVL-Eigenschaft in diesem Baum verletzt? Falls ja, nennen Sie den Knoten der zuletzt
eingefügt wurde, führen Sie die notwendigen Maßnahmen durch, um die AVL-Bedingung wieder
herzustellen, und zeichnen Sie den Baum in seinem korrigierten Zustand.
Führen Sie danach folgende Operationen in diesem AVL-Baum in der angegebenen Reihenfolge
durch und zeichnen Sie den Baum nach jeder Operation. Achten Sie darauf, dass die AVLEigenschaft immer erhalten bleibt.
5
• Fügen Sie 3 in den AVL-Baum ein.
• Fügen Sie 5 in den AVL-Baum ein.
• Löschen Sie 6 aus dem AVL-Baum (verwenden Sie falls notwendig den Successor als Ersatzelement).
Lösung Ja, die AVL-Eigenschaft in diesem Baum ist verletzt. Der Knoten 2 wurde als letztes
eingefügt. Dadurch erfüllt der Teilbaum mit der Wurzel 8 nicht mehr die AVL-Eigenschaft. ⇒
Der Teilbuam mit der Wurzel 8 muss nach rechts rotiert werden. Dadurch erhält der Teilbaum
das Element 6 als neue Wurzel.
10
6
16
2
8
14
22
18
• 3 in den AVL-Baum einfügen: Hier wird die 3 einfach als rechtes Kind von 2 eingefügt.
Es sind keine weiteren Schritte notwendig.
10
6
16
2
8
14
22
3
18
• 5 in den AVL-Baum einfügen: Hier wird die 5 als rechtes Kind von 3 eingefügt und
dadurch wird die AVL-Bedingung verletzt. ⇒ Der Teilbaum mit der Wurzel 2 wird nach
links rotiert, wodurch die 3 die neue Wurzel dieses Teilbaums wird.
10
6
3
2
16
8
5
14
22
18
• 6 aus dem AVL-Baum löschen: Hier wird 6 aus dem Baum rausgelöscht und durch 8
ersetzt. Dadurch entsteht wieder ein ungültiger AVL-Baum, denn der Teilbaum mit der
Wurzel 8 erfüllt nicht die AVL-Eigenschaft. ⇒ Der Teilbaum muss nach rechts rotiert
werden. Dadurch wird die 3 zur neuen Wurzel und die 5 wird links an die 8 angehängt.
6
10
3
16
2
8
5
14
22
18
Listing 2: Check ob es sich um gültige Suchbäume handelt. (Für Klasse avl tree.h siehe Listing 4)
1
2
// This Project is written in C ++11 , so use following command to compile it :
// g ++ - ggdb - std = c ++11 -o bsp2 bsp2 . cpp
3
4
5
# include < iostream >
# include " avl_tree . h "
6
7
8
9
10
11
12
13
int main (){
avl_tree < int > t ;
static const int inserts [] = {10 , 8 , 16 , 6 , 14 , 22 , 18};
std :: vector < int > ins ( inserts , inserts + sizeof ( inserts ) / sizeof ( inserts
for ( int i : ins ) {
t . insert ( i );
}
14
std :: cout << std :: endl <<t . to_string (2) << std :: endl ;
15
16
t . insert (2);
17
18
std :: cout << std :: endl <<t . to_string (2) << std :: endl ;
19
20
t . insert (3);
21
22
std :: cout << std :: endl <<t . to_string (2) << std :: endl ;
23
24
t . insert (5);
25
26
std :: cout << std :: endl <<t . to_string (2) << std :: endl ;
27
28
return 0;
29
30
}
Aufgabe 3 Vergleichen Sie die Datenstrukturen doppelt verkettete, zyklische Liste (aufsteigend sortiert), doppelt verkettete, zyklische Liste (nicht sortiert), natürlicher binärer Suchbaum
und AVL-Baum bezüglich ihres Zeitaufwandes für die Suche nach einem Schlüssel k und die
7
Bestimmung des größten Elementes im Best- und Worst-Case in Θ-Notation in Abhängigkeit
der Anzahl n der gespeicherten Elemente.
Lösung
i) Suche nach dem Schlüssel k
• aufsteigend sortierte doppelt verkettete Zyklische Liste
Best-Case: Θ(1)
Worst-Case: Θ(n/2) = Θ(n)
• unsortierte doppelt verkettete Zyklische Liste
Best-Case: Θ(1)
Worst-Case: Θ(n)
• natürlicher binärer Suchbaum
Best-Case: Θ(1)
Worst-Case: Θ(n)
• AVL-Baum
Best-Case: Θ(1)
Worst-Case: Θ(log(n))
ii) Bestimmung des größten Elements
• aufsteigend sortierte doppelt verkettete Zyklische Liste
Best-Case: Θ(1)
Worst-Case: Θ(1)
• unsortierte doppelt verkettete Zyklische Liste
Best-Case: Θ(1)
Worst-Case: Θ(n)
• natürlicher binärer Suchbaum
Best-Case: Θ(1)
Worst-Case: Θ(n)
• AVL-Baum
Best-Case: Θ(1)
Worst-Case: Θ(log(n))
Aufgabe 4
Aus folgendem B-Baum der Ordnung 3 soll der Schlüssel 8 entfernt werden:
8
10
8
20
5
9
12
21 29
Zeichnen Sie den Baum nach jedem Schritt der Reorganisation, die notwendig ist, um wieder
einen gültigen B-Baum zu erhalten (die leeren, schwarz dargestellten Blätter können bei der
Zeichnung entfallen).
Lösung
i) Löschen des Elements mit dem Schlüssel 8 un erstellung eines neuen Knotens
mit den beiden Schlüsseln 5 und 9:
10
8
5
20
9
12
21
29
ii) Das Element mit dem Schlüssel 20 nach oben verschieben:
10
5
9
20
12
21
29
iii) Die Schlüssel 10 und 20 sind nun die neue Wurzel:
10
5
9
20
12
21
29
9
Aufgabe 5
Geben Sie den Zustand einer Hashtabelle der Länge 13 an, wenn die Schlüssel
h5, 1, 16, 22, 14, 29, 32, 27, 2i
in gegebener Reihenfolge in die anfangs leere Datenstruktur eingefügt werden und ein offenes
Hashverfahren mit der Hashfunktion h(k) = k mod 13 sowie
(a) lineares Sondieren (Schrittweite 2)
(b) Double Hashing (h0 (k) = 1 + (k mod 5))
verwendet wird.
Vergleichen Sie die Anzahl der beim Einfügen betrachteten Hashtabellenplätze für die angegebenen Sondierungsfunktionen.
Lösung
Schlüssel und Wert der Hashfunktion:
k
h1 (k)
h2 (k)
5
5
1
1
1
2
16
3
2
22
9
3
14
1
5
29
3
5
32
6
3
27
1
3
2
2
3
(a) lineares Sondieren (Schrittweite 2)
i) Einfügen von 5 (da die Tabelle leer ist, ist dies ohne Probleme möglich) 1 Vergleich:
0
1
2
3
4
5
5
6
7
8
9
10
11
12
ii) Einfügen von 1 (da die Tabelle fast leer ist, ist dies ohne Probleme möglich) 1 Vergleich:
0
1
1
2
3
4
5
5
6
7
8
9
10
11
12
iii) Einfügen von 16 (da die Tabelle fast leer ist, ist dies ohne Probleme möglich) 1 Vergleich:
0
1
1
2
3
16
4
5
5
6
7
8
9
10
11
12
iv) Einfügen von 22 (da die Tabelle fast leer ist, ist dies ohne Probleme möglich) 1 Vergleich:
0
1
1
2
3
16
4
5
5
6
7
8
9
22
10
11
12
v) Einfügen von 14 (hier gibts Kollissionen mit 1, 3 und 5, aber 7 ist frei) 4 Vergleiche:
0
1
1
2
3
16
4
5
5
6
7
14
8
9
22
10
11
12
vi) Einfügen von 29 (hier gibts Kollissionen mit 3, 5, 7 und 9, aber 11 ist frei) 5 Vergleiche:
10
0
1
1
2
3
16
4
5
5
6
7
14
8
9
22
10
11
29
12
vii) Einfügen von 32 (hier gibts keine Kollissionen, somit ist das Einfügen auf 6 ohne
Probleme möglich) 1 Vergleich:
0
1
1
2
3
16
4
5
5
6
32
7
14
8
9
22
10
11
29
12
viii) Einfügen von 27 (hier gibts Kollissionen mit 1, 3, 5, 7, 9 und 11, aber 0 ist frei) 7
Vergleiche:
0
27
1
1
2
3
16
4
5
5
6
32
7
14
8
9
22
10
11
29
12
ix) Einfügen von 2 (hier gibts keine Kollissionen, somit ist das Einfügen auf 2 ohne Probleme möglich) 1 Vergleich:
0
27
1
1
2
2
3
16
4
5
5
6
32
7
14
8
9
22
10
11
29
12
⇒ 22 Vergleiche sind bei diesem offenen Hashverfahren notwendig.
(b) Double Hashing (h0 (k) = 1 + (k mod 5))
i) Einfügen von 5 (da die Tabelle leer ist, ist dies ohne Probleme möglich) 1 Vergleich:
0
1
2
3
4
5
5
6
7
8
9
10
11
12
ii) Einfügen von 1 (da die Tabelle fast leer ist, ist dies ohne Probleme möglich) 1 Vergleich:
0
1
1
2
3
4
5
5
6
7
8
9
10
11
12
iii) Einfügen von 16 (da die Tabelle fast leer ist, ist dies ohne Probleme möglich) 1 Vergleich:
0
1
1
2
3
16
4
5
5
6
7
8
9
10
11
12
iv) Einfügen von 22 (da die Tabelle fast leer ist, ist dies ohne Probleme möglich) 1 Vergleich:
0
1
1
2
3
16
4
5
5
6
7
8
9
22
10
11
12
v) Einfügen von 14 (hier gibts eine Kollission mit 1, aber 6 ist frei) 2 Vergleiche:
0
1
1
2
3
16
4
5
5
6
14
7
8
9
22
10
11
12
vi) Einfügen von 29 (hier gibts eine Kollission mit 3, aber 8 ist frei) 2 Vergleiche:
0
1
1
2
3
16
4
5
5
6
14
7
8
29
9
22
10
11
12
vii) Einfügen von 32 (hier gibts Kollissionen mit 6 und 9, aber 12 ist frei) 3 Vergleich:
11
0
1
1
2
3
16
4
5
5
6
14
7
8
29
9
22
10
11
12
32
viii) Einfügen von 27 (hier gibts eine Kollission mit 1, aber 4 ist frei) 2 Vergleiche:
0
1
1
2
3
16
4
27
5
5
6
14
7
8
29
9
22
10
11
12
32
ix) Einfügen von 2 (hier gibts keine Kollissionen, somit ist das Einfügen auf 2 ohne Probleme möglich) 1 Vergleich:
0
1
1
2
2
3
16
4
27
5
5
6
14
7
8
29
9
22
10
11
12
32
⇒ 14 Vergleiche sind bei diesem offenen Hashverfahren notwendig.
⇒ Die Sondierungsmethode Double-Hashing ist wesentlich Effizienter in diesem Fall (wie sonst
meist auch), denn die 2. von der 1. unabhängigen Hashfunktion bewirkt eine viel bessere Streuung der Werte in der Tabelle.
Aufgabe 6 Breitensuche ist ein Verfahren zum Durchsuchen bzw. Durchlaufen von Knoten
eines Graphen ähnlich der in der Vorlesung behandelten Tiefensuche. Auch hier geht man von
einem Startknoten u aus, allerdings unterscheiden sich Tiefen- und Breitensuche hinsichtlich der
Reihenfolge, in der weitere Knoten des Graphen abgearbeitet bzw. besucht werden. Wir gehen
im Folgenden von einem ungerichteten Graphen aus.
Beginnend mit dem Startknoten u werden bei der Breitensuche zunächst alle zu u adjazenten
Knoten besucht, d.h. alle Knoten v, für die eine Kante (u, v) im Graphen existiert; zusätzlich
werden alle diese Knoten v in einer Warteschlange gespeichert. Die Breitensuche bearbeitet also
zuerst immer alle direkt benachbarten Knoten und folgt nicht – wie die Tiefensuche – gleich
einem Pfad in die Tiefe.
Nachdem nun alle adjazenten Knoten von u betrachtet wurden, wird der erste Knoten der
Warteschlange entnommen und für diesen das Verfahren wiederholt. Dies wird nun so lange
fortgesetzt, bis entweder die Warteschlange leer ist oder bis – wenn man nach einem bestimmten
Knoten sucht – dieser gefunden wurde. Wie auch bei der Tiefensuche werden durch Markieren
bereits bearbeiteter Knoten Mehrfachbesuche verhindert.
Gegeben sei nun die Datenstruktur Queue (Warteschlange), welche eine beliebige Menge an
Objekten aufnehmen kann und diese gemäß der Reihenfolge ihres Einfügens zurück liefert.
Folgende Operationen werden von einer Queue Q zur Verfügung gestellt:
• Q.isEmpty(): Liefert true zurück, falls die Queue Q keine Elemente enthält, und false
sonst.
• Q.put(x): Fügt das Element x der Queue Q hinzu.
• Q.get(): Entfernt das älteste Element in der Queue Q und liefert dieses zurück.
Benutzen Sie die Queue, um eine nicht-rekursive Version der Breitensuche zu entwerfen. Beschreiben Sie erst in wenigen Worten den Ablauf Ihres Algorithmus und geben Sie diesen dann
12
in Pseudocode an. Die Queue können Sie dabei als Black Box“ betrachten, d.h., Sie können
”
sie benutzen, ohne die genaue Funktionsweise explizit als Pseudocode ausarbeiten zu müssen.
Lösung
1. Alle eventuell markierten Knoten entmarkieren und die Queue leeren.
2. Anschließend wird der Startknoten in die Queue gelegt und markiert.
3. Das Erste Element wird aus der Queue genommen und für diesen Knoten werden alle
Nachbarknoten bestimmt, die dann sofern sie nicht bereits markiert wurden in die Queue
gelegt und markiert werden.
4. Es wird solange der Schritt 3 wiederholt, bis die Queue leer ist.
Algorithmus Breitensuche(G, s):
Eingabe: Graph G = (V, E); Knoten s ∈ V
Ausgabe: alle Knoten G, di von s aus erreichbar sind
1: Initialisierung: setze markiert[v] = 0 für alle v;
// Löschen der Elemente in der Queue
2: solange Q.isEmpty() == F alsch {
3:
Q.get();
4: }
5: Q.put(s);
6: markiert[s] = 1;
7: solange Q.isEmpty() == F alsch {
8:
v = Q.get();
9:
Ausgabe von v;
10:
für alle Knoten w aus N (v) {
11:
falls markiert[w] == 0 dann {
12:
Q.put(w);
13:
markiert[w] = 1;
14:
}
15:
}
16: }
Aufgabe 7 Auf dem gegebenen Graphen wird die aus dem Skriptum bekannte Tiefensuche
und die aus dem vorigen Übungsbeispiel bekannte Breitensuche durchgeführt.
13
Welche der folgenden Listen von besuchten Knoten können dabei in genau dieser Reihenfolge
entstehen? Hinweis: Die Nachbarn eines Knotens können in beliebiger Reihenfolge abgearbeitet
werden.
Reihenfolge
ABCDEFGHIK
ABDCGHIKFE
BADCGHIKFE
ABCDHKFEIH
KEFHIGCDAB
CGIKEFHBDA
Tiefensuche
Breitensuche
x
x
x
x
Aufgabe 8 Gegeben ist ein gerichteter Graph G = (V, E), ein Startknoten s ∈ V und ein
Zielknoten t ∈ V . Die Distanzen zwischen den Knoten sind in der Adjazenzmatrix A gegeben.
Entwerfen Sie einen Greedy-Algorithmus in Pseudocode, der (mit der Motivation einen
möglichst kurzen Weg vom Startknoten s zum Zielknoten t zu finden) wie folgt vorgeht: Ausgehend vom Startknoten s wählt dieser Algorithmus bei jedem Knoten jeweils immer die kürzeste
noch nicht verwendete Kante, um dem Zielknoten t auf einem zusammenhängenden Pfad näher
zu kommen.
Liefert dieser Algorithmus immer den kürzesten Pfad? Begründen Sie Ihre Antwort.
Veranschaulichen Sie die Funktionsweise des Algorithmus anhand eines Beispiels (Graph mit 4
– 5 Knoten), bzw. geben Sie ein möglichst einfaches Gegenbeispiel an.
Lösung Der Folgende Algorithmus verwendet eine einfach verkettete Liste L, die alle Kanten
enthält, die der Algorithums auf dem Weg von Knoten s nach e gefunden hat. In die Liste kann
mittels L.push back(e) ein Element eingefügt werden. Die Liste kann mit L.clear() gelöscht
werden.
Algorithmus Breitensuche(G, s):
Eingabe: Graph G = (V, E) mit Gewichten we ∀e ∈ E; Knoten s, e ∈ V
Ausgabe: möglichst kurzer Pfad von s nach e (ist aber nicht unbedingt der kürzeste)
14
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
Initialisierung: setze markiert[i] = 0 für alle i;
// Löschen der Elemente in der Liste
L.clear();
k = s;
solange k 6= e {
sdist=NULL;
nextk=NULL;
für alle Knoten l aus N (k) {
edge = e(k, l); // edge enthält die Kante zwischen den Knoten k und l
falls markiert[edge] == 0 UND (sdist == N U LL ODER w(edge) < sdist) dann {
sdist=w(edge); // sdist enthält die Distanz zwischen den Knoten k und l
nextk=l;
}
}
falls sdist == N U LL dann {
Fehler, es existiert kein Weg von s nach e.
}
k = nextk;
markiert[edge] = 1;
L.push back(edge);
}
Der in Abbildung 1 gezeigte Graph ist z.B. ein Paradebeispiel dafür, dass der Algorithmus nicht
immer den kürzesten Pfad vom Knoten s nach e findet. (Denn der optimalste Weg wäre der
direkte zwischen s und e.)
Das Problem an diesem Algorithmus ist, dass er sich immer nur die lokalen Bestwerte vergleicht
und keinen Blick fürs große ganze hat.
A
2
5
E
6
start
16
S
15
4
B
15
C
Abbildung 1: Beispiel für einen Graph, der sich nicht gut für den Greedy-Algorithmus eignet.
A. Bin-Tree
A.1. bin tree.h
15
1
2
Listing 3: Klasse bin tree (Für Klasse avl tree.h siehe Listing 4)
# ifndef BIN_TREE_H
# define BIN_TREE_H
3
4
5
6
7
8
9
# include
# include
# include
# include
# include
# include
< memory >
< stdexcept >
< string >
< sstream >
< vector >
< iomanip >
10
11
# include < math .h >
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
template < typename T >
class bin_tree {
protected :
template < typename U >
class element {
private :
typedef U data_type ;
public :
element () = delete ;
element ( data_type _data );
element ( data_type _data , element * _parent );
element ( data_type _data , element * _parent , element * _left , el
data_type data ;
int height ;
element * left ;
element * right ;
element * parent ;
~ element ();
};
template < typename U >
class limit {
private :
typedef U data_type ;
data_type lim ;
bool undef ;
public :
limit ();
limit ( data_type _limit );
data_type get ();
bool is_undef ();
void set ( data_type _limit );
void set_undef ();
};
46
47
public :
16
48
49
50
51
52
typedef T data_type ;
typedef element < data_type > elem ;
bin_tree ();
bin_tree ( data_type data );
~ bin_tree ();
53
54
55
56
57
virtual void insert ( data_type data );
void insert_manually ( data_type data ,
data_type parent_data , bool left_or_right );
void del ( data_type data );
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
std :: string to_string ( int width =2) const ;
std :: string inorder () const ;
std :: string preorder () const ;
std :: string postorder () const ;
int get_height () const ;
bool c h e c k _ b i n a r y _ s e a r c h _ t r e e () const ;
/* void insert_manually ( data_type data , data_type parent_data , bool l
data_type search ( data_type data );
void del ( data_type data );
*/
protected :
int get_height ( const elem * current ) const ;
void calc_height ( elem * current );
void c a l c _ h e i g h t _ r e c u r s i v e ( elem * current );
73
74
75
76
void set_left ( elem * current , elem * left );
void set_right ( elem * current , elem * right );
void set_parent ( elem * current , elem * parent );
77
78
79
80
std :: string inorder ( const elem * current ) const ;
std :: string preorder ( const elem * current ) const ;
std :: string postorder ( const elem * current ) const ;
81
82
elem * root ;
83
84
85
86
87
88
private :
virtual void insert ( data_type data , elem * parent );
void to_vector ( std :: vector < std :: vector < std :: shared_ptr < data_type > > > &
const elem * current ) const ;
elem * search ( data_type data , elem * current ) const ;
89
90
91
92
93
elem
elem
elem
elem
* minimum ( elem * current ) const ;
* maximum ( elem * current ) const ;
* successor ( elem * current ) const ;
* predecessor ( elem * current ) const ;
94
95
bool c h e c k _ b i n a r y _ s e a r c h _ t r e e ( const elem *e , limit < data_type > ulimit ,
17
96
};
97
98
99
100
template < typename T >
bin_tree <T >:: bin_tree ( data_type data )
: root ( new elem ( data )){}
101
102
103
template < typename T >
bin_tree <T >:: bin_tree (): root ( nullptr ){}
104
105
106
107
108
109
110
template < typename T >
bin_tree <T >::~ bin_tree (){
if ( root ) {
delete root ;
}
}
111
112
113
114
115
116
117
118
119
template < typename T >
int bin_tree <T >:: get_height ( const elem * current ) const {
if ( current ) {
return current - > height ;
} else {
return -1;
}
}
120
121
122
123
124
template < typename T >
bool bin_tree <T >:: c h e c k _ b i n a r y _ s e a r c h _ t r e e () const {
return c h e c k _ b i n a r y _ s e a r c h _ t r e e ( root , limit < data_type >() , limit < data_type
}
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
template < typename T >
bool bin_tree <T >:: c h e c k _ b i n a r y _ s e a r c h _ t r e e ( const elem *e , limit < data_type > ul
if (! llimit . is_undef () && e - > data <= llimit . get ()) {
return false ;
}
if (! ulimit . is_undef () && e - > data > ulimit . get ()) {
return false ;
}
if (e - > left ) {
bool res ( c h e c k _ b i n a r y _ s e a r c h _ t r e e (e - > left , limit < data_type >( e - > data ) ,
if (! res ) {
return false ;
}
}
if (e - > right ) {
return res ( c h e c k _ b i n a r y _ s e a r c h _ t r e e (e - > right , ulimit , limit < data_type
}
return true ;
18
144
}
145
146
147
148
149
template < typename T >
int bin_tree <T >:: get_height () const {
return get_height ( root );
}
150
151
152
153
154
155
156
157
158
159
template < typename T >
void bin_tree <T >:: calc_height ( elem * current ){
int height = -1;
height = get_height ( current - > left );
if ( get_height ( current - > right ) > height ){
height = get_height ( current - > right );
}
current - > height = ++ height ;
}
160
161
162
163
164
165
166
167
168
169
170
template < typename T >
void bin_tree <T >:: c a l c _ h e i g h t _ r e c u r s i v e ( elem * current ){
if ( current - > left ) {
c a l c _ h e i g h t _ r e c u r s i v e ( current - > left );
}
if ( current - > right ) {
c a l c _ h e i g h t _ r e c u r s i v e ( current - > right );
}
calc_height ( current );
}
171
172
173
174
175
176
177
178
179
template < typename T >
void bin_tree <T >:: insert ( data_type data ){
if (! root ) {
root = new elem ( data );
} else {
insert ( data , root );
}
}
180
181
182
183
184
185
186
187
188
189
190
191
template < typename T >
void bin_tree <T >:: insert_manually ( data_type data ,
data_type parent_data , bool left_or_right ){
elem * parent_node ( search ( parent_data , root ));
if ( parent_node ) {
if ( left_or_right ) {
set_left ( parent_node , new elem ( data ));
} else {
set_right ( parent_node , new elem ( data ));
}
} else {
19
std :: stringstream ss ;
ss << " Element " << parent_data << " doesn ’t exist . " ;
throw std :: runtime_error ( ss . str ());
192
193
194
}
195
196
}
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
template < typename T >
void bin_tree <T >:: insert ( data_type data , elem * parent ) {
if ( data < parent - > data ) {
if (! parent - > left ) {
set_left ( parent , new elem ( data , parent ));
} else {
insert ( data , parent - > left );
}
} else {
if (! parent - > right ) {
set_right ( parent , new elem ( data , parent ));
} else {
insert ( data , parent - > right );
}
}
}
214
215
216
217
218
219
220
221
222
223
224
template < typename T >
void bin_tree <T >:: set_left ( elem * current , elem * left ){
current - > left = left ;
calc_height ( current );
if ( current - > parent ) {
for ( elem * p ( current - > parent ); p ; p =p - > parent ) {
calc_height ( p );
}
}
}
225
226
227
228
229
230
231
232
233
234
235
template < typename T >
void bin_tree <T >:: set_right ( elem * current , elem * right ){
current - > right = right ;
calc_height ( current );
if ( current - > parent ) {
for ( elem * p ( current - > parent ); p ; p =p - > parent ) {
calc_height ( p );
}
}
}
236
237
238
239
template < typename T >
void bin_tree <T >:: set_parent ( elem * current , elem * parent ){
current - > parent = parent ;
20
calc_height ( current );
for ( elem * p ( current - > parent ); p ; p =p - > parent ) {
calc_height ( p );
}
240
241
242
243
244
}
245
246
247
248
249
250
251
252
253
254
template < typename T >
std :: string bin_tree <T >:: to_string ( int width ) const {
if ( root ) {
// generate an empty - string for empty - elements
std :: stringstream data_stream ;
data_stream << std :: setfill ( ’ ’ );
data_stream . width ( width );
data_stream << " " ;
std :: string empty ( data_stream . str ());
255
std :: vector < std :: vector < std :: shared_ptr < data_type > > > svec ;
std :: stringstream ret ;
256
257
258
to_vector ( svec , root );
259
260
int step =1;
int chars_last_line = pow (2 , root - > height )*( width +1) -1;
for ( typename std :: vector < std :: vector < std :: shared_ptr < data_type > > >:: c
it = svec . begin (); it != svec . end (); ++ it ,++ step ) {
int pos = pow (2 , root - > height - step +1)* width ;
for ( typename std :: vector < std :: shared_ptr < data_type > >:: const_itera
tit != it - > end (); ++ tit ) {
data_stream . str ( " " );
if (* tit ) {
data_stream << std :: setw ( width )
<< std :: setfill ( ’0 ’) << ** tit ;
} else {
data_stream << empty ;
}
ret << std :: setw ( pos ) << data_stream . str ();
ret << std :: setw ( pos ) << " " ;
}
ret << std :: endl ;
}
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
return ret . str ();
} else {
return " empty Tree " ;
}
281
282
283
284
285
}
286
287
template < typename T >
21
288
289
290
291
292
293
void bin_tree <T >:: to_vector (
std :: vector < std :: vector < std :: shared_ptr < data_type > > > & svec ,
const elem * current ) const {
std :: vector < std :: shared_ptr < data_type > > tmp_vec ;
tmp_vec . push_back ( std :: shared_ptr < data_type >( new data_type ( current - > data )
svec . push_back ( tmp_vec );
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
if ( current - > left || current - > right ) {
if ( current - > left && current - > right ) {
std :: vector < std :: vector < std :: shared_ptr < data_type > > > leftvec , righ
to_vector ( leftvec , current - > left );
to_vector ( rightvec , current - > right );
typename std :: vector < std :: vector < std :: shared_ptr < data_type > > >:: c
rit ( rightvec . begin ()) , lit = leftvec . begin ();
for ( int i =0; i < current - > height ; i ++) {
// because first element is set above ...
std :: vector < std :: shared_ptr < data_type > > tmp ;
if ( lit != leftvec . end ()) {
tmp . insert ( tmp . end () , lit - > begin () , lit - > end ());
lit ++;
} else {
for ( int j =0; j < pow (2 , i )/2; j ++) {
tmp . push_back ( std :: shared_ptr < data_type >());
}
}
if ( rit != rightvec . end ()) {
tmp . insert ( tmp . end () , rit - > begin () , rit - > end ());
rit ++;
} else {
for ( int j =0; j < pow (2 , i )/2; j ++) {
tmp . push_back ( std :: shared_ptr < data_type >());
}
}
svec . push_back ( tmp );
}
} else if ( current - > left ) {
std :: vector < std :: vector < std :: shared_ptr < data_type > > > leftvec ;
to_vector ( leftvec , current - > left );
for ( typename std :: vector < std :: vector < std :: shared_ptr < data_type > >
lit ( leftvec . begin ()); lit != leftvec . end (); lit ++) {
std :: vector < std :: shared_ptr < data_type > > tmp ;
tmp . insert ( tmp . end () , lit - > begin () , lit - > end ());
for ( int i =0; i < lit - > size (); i ++) {
tmp . push_back ( std :: shared_ptr < data_type >());
}
svec . push_back ( tmp );
}
} else if ( current - > right ) {
22
std :: vector < std :: vector < std :: shared_ptr < data_type > > > rightvec ;
to_vector ( rightvec , current - > right );
for ( typename std :: vector < std :: vector < std :: shared_ptr < data_type > >
rit ( rightvec . begin ()); rit != rightvec . end (); rit ++) {
std :: vector < std :: shared_ptr < data_type > > tmp ;
for ( int i =0; i < rit - > size (); i ++) {
tmp . push_back ( std :: shared_ptr < data_type >());
}
tmp . insert ( tmp . end () , rit - > begin () , rit - > end ());
svec . push_back ( tmp );
}
335
336
337
338
339
340
341
342
343
344
345
}
} else {
// befuelle die restliche hoehe mit leeren zeichen ...
if ( current - > parent ) {
elem * tmp ( current - > parent );
int depth = 0;
while ( tmp ) {
depth ++;
tmp = tmp - > parent ;
}
for ( int i = depth +1; i <= root - > height ; i ++) {
std :: vector < std :: shared_ptr < data_type > > tmp ;
int chars_line = pow (2 , i - depth );
for ( int j =0; j < chars_line ; j ++) {
tmp . push_back ( std :: shared_ptr < data_type >());
}
svec . push_back ( tmp );
}
}
}
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
}
367
368
369
370
371
372
373
374
375
template < typename T >
std :: string bin_tree <T >:: inorder () const {
if ( root ) {
return inorder ( root );
} else {
return " empty Tree " ;
}
}
376
377
378
379
380
381
382
template < typename T >
std :: string bin_tree <T >:: inorder ( const elem * current ) const {
std :: stringstream ret ;
if ( current - > left ) {
ret << inorder ( current - > left );
}
23
ret << current - > data << " , " ;
if ( current - > right ) {
ret << inorder ( current - > right );
}
return ret . str ();
383
384
385
386
387
388
}
389
390
391
392
393
394
395
396
397
template < typename T >
std :: string bin_tree <T >:: preorder () const {
if ( root ) {
return preorder ( root );
} else {
return " empty Tree " ;
}
}
398
399
400
401
402
403
404
405
406
407
408
409
410
template < typename T >
std :: string bin_tree <T >:: preorder ( const elem * current ) const {
std :: stringstream ret ;
ret << current - > data << " , " ;
if ( current - > left ) {
ret << preorder ( current - > left );
}
if ( current - > right ) {
ret << preorder ( current - > right );
}
return ret . str ();
}
411
412
413
414
415
416
417
418
419
template < typename T >
std :: string bin_tree <T >:: postorder () const {
if ( root ) {
return postorder ( root );
} else {
return " empty Tree " ;
}
}
420
421
422
423
424
425
426
427
428
429
430
template < typename T >
std :: string bin_tree <T >:: postorder ( const elem * current ) const {
std :: stringstream ret ;
if ( current - > left ) {
ret << postorder ( current - > left );
}
if ( current - > right ) {
ret << postorder ( current - > right );
}
ret << current - > data << " , " ;
24
return ret . str ();
431
432
}
433
434
435
436
437
438
439
440
441
442
443
444
445
template < typename T >
typename bin_tree <T >:: elem * bin_tree <T >:: search ( data_type data , elem * current
if ( current - > data == data ) {
return current ;
} else if ( current - > left && data < current - > data ){
return search ( data , current - > left );
} else if ( current - > right ){
return search ( data , current - > right );
} else {
return nullptr ;
}
}
446
447
448
449
450
451
452
453
454
template < typename T >
typename bin_tree <T >:: elem * bin_tree <T >:: minimum ( elem * current ) const {
if ( current - > left ) {
return minimum ( current - > left );
} else {
return current ;
}
}
455
456
457
458
459
460
461
462
463
template < typename T >
typename bin_tree <T >:: elem * bin_tree <T >:: maximum ( elem * current ) const {
if ( current - > right ) {
return maximum ( current - > right );
} else {
return current ;
}
}
464
465
466
467
468
469
470
471
472
473
474
475
476
template < typename T >
typename bin_tree <T >:: elem * bin_tree <T >:: successor ( elem * current ) const {
if ( current - > right ) {
return minimum ( current - > right );
} else {
if ( current - > parent && current - > parent - > right == current ) {
return successor ( current - > parent );
} else {
return current - > parent ;
}
}
}
477
478
template < typename T >
25
479
480
481
482
483
484
485
486
487
488
489
typename bin_tree <T >:: elem * bin_tree <T >:: predecessor ( elem * current ) const {
if ( current - > left ) {
return maximum ( current - > left );
} else {
if ( current - > parent && current - > parent - > left == current ) {
return predecessor ( current - > parent );
} else {
return current - > parent ;
}
}
}
490
491
492
493
494
495
template < typename T >
void bin_tree <T >:: del ( data_type data ){
elem * del ( search ( data , root ));
if ( del ) {
std :: unique_ptr < elem > r ;
496
497
498
499
500
501
502
if (! del - > left || ! del - > right ) {
r . reset ( del );
} else {
r . reset ( successor ( del ));
del - > data = r - > data ;
}
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
elem * p ;
if (r - > left ) {
p = r - > left ;
} else {
p = r - > right ;
}
if ( p ) {
p - > parent = r - > parent ;
}
if (! r - > parent ) {
root = p ;
calc_height ( root );
} else {
if ( r . get ()== r - > parent - > left ) {
set_left (r - > parent , p );
} else {
set_right (r - > parent , p );
}
}
523
524
525
526
// this is importaint , if you forget this , every child would be delete
r - > left = nullptr ;
r - > right = nullptr ;
26
} else {
std :: stringstream ss ;
ss << " Element " << data << " doesn ’t exist . " ;
throw std :: runtime_error ( ss . str ());
}
527
528
529
530
531
532
}
533
534
535
536
537
538
539
540
541
542
template < typename T >
template < typename U >
bin_tree <T >:: element <U >:: element ( data_type _data )
: data ( _data ) , parent ( nullptr ) , left ( nullptr ) , right ( nullptr ) , height (0) {
543
544
545
546
547
template < typename T >
template < typename U >
bin_tree <T >:: element <U >:: element ( data_type _data , element * _parent )
: data ( _data ) , parent ( _parent ) , left ( nullptr ) , right ( nullptr ) , height (0) {
548
549
550
551
552
553
template < typename T >
template < typename U >
bin_tree <T >:: element <U >:: element ( data_type _data , element * _parent ,
element * _left , element * _right )
: data ( _data ) , parent ( _parent ) , left ( _left ) , right ( _right ) , height (0) {}
554
555
556
557
558
559
560
561
562
563
564
template < typename T >
template < typename U >
bin_tree <T >:: element <U >::~ element (){
if ( left ) {
delete left ;
}
if ( right ) {
delete right ;
}
}
565
566
567
568
569
570
template < typename T >
template < typename U >
bin_tree <T >:: limit <U >:: limit ()
: lim () , undef ( true ) {}
571
572
573
574
template < typename T >
template < typename U >
bin_tree <T >:: limit <U >:: limit ( data_type _limit )
27
575
: lim ( _limit ) , undef ( false ) {}
576
void set_undef ();
577
578
579
580
581
582
583
template < typename T >
template < typename U >
bool bin_tree <T >:: limit <U >:: is_undef (){
return undef ;
}
584
585
586
587
588
589
template < typename T >
template < typename U >
U bin_tree <T >:: limit <U >:: get (){
return lim ;
}
590
591
592
593
594
595
596
template < typename T >
template < typename U >
void bin_tree <T >:: limit <U >:: set ( data_type _limit ){
undef = false ;
lim = _limit ;
}
597
598
599
600
601
602
template < typename T >
template < typename U >
void bin_tree <T >:: limit <U >:: set_undef (){
undef = true ;
}
603
604
# endif
A.2. avl tree.h
Listing 4: Klasse avl tree
1
2
# ifndef AVL_TREE_H
# define AVL_TREE_H
3
4
# include " bin_tree . h "
5
6
7
8
9
10
11
12
13
14
template < typename T >
class avl_tree : public bin_tree <T >{
private :
typedef T data_type ;
typedef typename bin_tree <T >:: elem elem ;
public :
avl_tree (): bin_tree <T >(){};
avl_tree ( data_type data ): bin_tree <T >( data ){};
virtual void insert ( data_type data ){ bin_tree <T >:: insert ( data );};
28
15
private :
virtual void insert ( data_type data , elem * parent );
16
17
18
elem
elem
elem
elem
19
20
21
22
23
* rotate_to_right ( elem * current );
* rotate_to_left ( elem * current );
* d o u b l e _ r o t a t e _ r i g h t _ l e f t ( elem * current );
* d o u b l e _ r o t a t e _ l e f t _ r i g h t ( elem * current );
};
24
25
26
27
28
29
30
31
32
33
template < typename T >
void avl_tree <T >:: insert ( data_type data , elem * parent ) {
if ( data < parent - > data ) {
if (! parent - > left ) {
this - > set_left ( parent , new elem ( data , parent ));
} else {
insert ( data , parent - > left );
}
this - > calc_height ( parent );
34
35
36
37
38
if ( this - > get_height ( parent - > right ) - this - > get_height ( parent - > left ) ==
elem * father ( parent - > parent );
if ( this - > get_height ( parent - > left - > left ) > this - > get_height ( parent
elem * tmp ( this - > rotate_to_right ( parent ));
39
40
this - > set_parent ( tmp , father );
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
if ( father && father - > data > tmp - > data ){
this - > set_left ( father , tmp );
} else if ( father && father - > data <= tmp - > data ){
this - > set_right ( father , tmp );
} else {
this - > root = tmp ;
}
} else {
elem * tmp ( this - > d o u b l e _ r o t a t e _ l e f t _ r i g h t ( parent ));
this - > set_parent ( tmp , father );
if ( father ){
this - > set_right ( father , tmp );
} else {
this - > root = tmp ;
}
}
}
} else {
if (! parent - > right ) {
this - > set_right ( parent , new elem ( data , parent ));
} else {
29
insert ( data , parent - > right );
63
}
this - > calc_height ( parent );
64
65
66
if ( this - > get_height ( parent - > right ) - this - > get_height ( parent - > left ) ==
elem * father ( parent - > parent );
if ( this - > get_height ( parent - > right - > right ) > this - > get_height ( pare
elem * tmp ( this - > rotate_to_left ( parent ));
this - > set_parent ( tmp , father );
if ( father ){
this - > set_left ( father , tmp );
} else {
this - > root = tmp ;
}
} else {
elem * tmp ( this - > d o u b l e _ r o t a t e _ r i g h t _ l e f t ( parent ));
this - > set_parent ( tmp , father );
this - > set_right ( father , tmp );
if ( father ){
this - > set_right ( father , tmp );
} else {
this - > root = tmp ;
}
}
}
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
}
88
89
}
90
91
92
93
94
95
96
97
98
template < typename T >
typename avl_tree <T >:: elem * avl_tree <T >:: rotate_to_right ( elem * current ){
if ( current && current - > left ) {
elem * tmp ( current - > left );
this - > set_left ( current , tmp - > right );
if ( current - > left ) {
this - > set_parent ( current - > left , current );
}
99
this - > set_right ( tmp , current );
this - > calc_height ( current );
this - > calc_height ( tmp );
100
101
102
103
tmp - > parent = nullptr ;
current - > parent = tmp ;
current = tmp ;
104
105
106
107
}
return current ;
108
109
110
}
30
111
112
113
114
115
template < typename T >
typename avl_tree <T >:: elem * avl_tree <T >:: rotate_to_left ( elem * current ){
if ( current && current - > right ) {
elem * tmp ( current - > right );
116
this - > set_right ( current , tmp - > left );
if ( current - > right ) {
this - > set_parent ( current - > right , current );
}
117
118
119
120
121
tmp - > left = current ;
this - > calc_height ( current );
this - > calc_height ( tmp );
122
123
124
125
tmp - > parent = nullptr ;
current - > parent = tmp ;
current = tmp ;
126
127
128
}
return current ;
129
130
131
}
132
133
134
135
136
137
template < typename T >
typename avl_tree <T >:: elem * avl_tree <T >:: d o u b l e _ r o t a t e _ l e f t _ r i g h t ( elem * curre
this - > set_left ( current , rotate_to_left ( current - > left ));
return rotate_to_right ( current );
}
138
139
140
141
142
143
template < typename T >
typename avl_tree <T >:: elem * avl_tree <T >:: d o u b l e _ r o t a t e _ r i g h t _ l e f t ( elem * curre
this - > set_right ( current , rotate_to_right ( current - > right ));
return rotate_to_left ( current );
}
144
145
# endif
31
Herunterladen