Aufgaben mit Lösungen

Werbung
Aufgaben zur Algorithmentheorie
22. März 2004
1
Einleitung
Diese Aufgabensammlung wird für die Informatikstudenten der Deutschsprachigen Ingenieurausbildung der TU Budapest angefertigt, insbesondere als ein Hilfsmittel zu den Übungen Algorithmentheorie. Die Aufgabensammlung ist noch nicht
fertig, also können Fehler durchaus vorkommen. Damit diese eliminiert werden
können, werden auch die Leser geboten, gefundene Fehler den Autoren zu melden.
2
Inhaltsverzeichnis
Aufgaben
4
1
Einleitende Aufgaben
4
2
Sortieren
5
3
Suchbäume
5
4
Hashing
6
5
Datenkomprimierung
7
6
Graphentheoretische Algorithmen
8
7
Die Sprache NP
10
Lösungen
13
1
Einleitende Aufgaben
13
2
Sortieren
18
3
Suchbäume
23
4
Hashing
29
5
Datenkomprimierung
30
6
Graphentheoretische Algorithmen
32
7
Die Sprache NP
42
3
Aufgaben
1
Einleitende Aufgaben
1.1. Untersuchen Sie, ob zwischen den folgenden Funktionen die Relationen
, , erfüllt sind!
,
a) und b) und c) und 1.2. Gegeben sind 9 Geldstücke, die gleich aussehen. 8 haben das gleiche Gewicht, das neunte ist aber verfälscht, und hat ein
a) kleineres
b) anderes
Gewicht. Wir können mit einer Waage Vergleiche machen. Geben Sie einen Algorithmus, der in möglichst wenig Vergleichen das falsche Geldstück findet!
1.3. Geben Sie einen Algorithmus, der die beiden Teilarrays "!#%$'&)( und "!*&+
10
10
%$,-( des Arrays .!/%$,-( in 32 Schritten, mit
42 Arbeitsspeicher vertauscht.
1.4.
Geben Sie einen effizienten Algorithmus, der alle Teilmengen der Menge
5
76896;:<:;:=6>@? ausschreibt; jede Teilmenge muss genau einmal ausgeschrieben werden, und die Kardinalität von zwei nacheinanderfolgenden Teilmengen darf höchstens um 1 verschieden sein.
10
0
A2 und 42 ?
1.5. Was bedeutet
1.6. Das Problem „Türme von Hanoi”. Es gibt eine Platte, auf der drei Nadeln befestigt sind. Man hat vierundsechzig Scheiben auf eine der Nadeln gesteckt, wobei
die größte Scheibe auf der Platte ruht, und die übrigen, immer kleiner werdend,
eine auf der anderen. Das Ziel ist, die Scheiben auf eine andere Nadel umzusetzen, wobei man nur jeweils eine Scheibe auf einmal umsetzen darf, und zwar so,
dass sich nie eine kleinere Scheibe unter einer größeren befindet.
Geben Sie einen Algorithmus, der dieses Problem in möglichst wenig Schritten
löst! Wieviele Schritte braucht man dafür mindestens?
4
2
Sortieren
2.1. Sortieren Sie die Liste 4, 11, 9, 10, 5, 6, 8, 1, 2, 16 mit merge sort, quick sort
und heap sort!
2.2. Wieviele Vergleiche sind benötigt, um das kleinste von Elementen zu finden? Und das zweitkleinste? Und das & -kleinste?
2.3. Geben Sie einen effizienten Algorithmus, der das zehntkleinste Element eines Heaps findet!
0
2.4. Beweisen Sie, dass die Konstruktion eines Heaps mindestens 2 Vergleiche benötigt!
0
2.5. 6 6;:;:;:=6 2 sind verschiedene ganze Zahlen. Wir möchten diese Zah
len der Grösse nach ordnen – entweder steigend oder fallend. Statt den üblichen
Vergleichen kann man solche Fragen stellen: Welches ist das mittlere von drei
Elementen?
0
Beweise: der effizienteste Algorithmus braucht 32 Schritte!
3
Suchbäume
3.1. Seien Elemente im binären Suchbaum und & Elemente im binären Such0
baum . (Die Elemente sind aus dem Universum 6 2 ). Gebe einen Algorithmus an, der alle & Elemente in Grössenordnung ausgibt! Was ist die Kost der
Methode?
3.2. Zeige, dass in einem binären Baum die Anzahl der Blätter genau mit eins
grösser ist, als die Anzahl solcher Punkten, die Grad 2 haben!
3.3. Sei ein vollständiger binärer Baum mit Knoten. Die Elemente in
seien die ganze Zahlen aus dem Intervall !# $ =( . Daraus folgt, dass genau eine
Zahl nicht vorkommt. Finde diese Zahl so schnell, wie möglich!
3.4. Ein binärer Baum hat die Eigenschaft, dass ausser den Blättern jeder Knotenpunkt Grad 2 hat. Weiterhin gilt, dass
0
0 3
& 22
0 0 22
Beweise, dass der Baum vollständig ist!
3.5. In einem 2-3 Baum sind die Elemente aus dem Intervall !/$ ( . In der
Wurzel befinden sich zwei Schlüsseln, der erste ist 17. Was kann der zweite sein?
5
3.6. Ein AVL-Baum kann mit Hilfe des inorder Durchlaufens als eine geordnete Liste interpretiert werden. Wie könnte man die Konkatenation von Listen mit
AVL-Bäumen realisieren? Präziser: seien und zwei AVL-Bäume so, dass je
der Schlüssel in kleiner ist als in . Vereinige und in einen AVL-Baum!
3.7. Punkte sind in dem 2-dimensionalen Koordinatensystem mit ihrer Koordinaten gegeben so, dass alle Koordinaten verschiedene Zahlen sind ( verschiedene Zahlen). Beweise, dass genau ein binärer Baum existiert so, dass die Knoten des Bäumes diese Punkten sind, und die ersten Koordinaten die SuchbaumEigenschaft, die zweiten Koordinaten die Heap-Eigenschaft erfüllen!
3.8. Konstruiere einen AVL-Baum aus den folgenden Zahlen: 6 '6896;6 96 '6 !
0 5
6 2 6
76896;: : :6 ?)6 6 3.9. Seien die Punkte auf der Ebene
0
gegeben. Gebe einen Algorithmus mit 7 32 Kost an, der entscheidet, ob
zwei Punkte näher als 2 existieren!
3.10. In einen 2-3 Baum wurden 1000 neue Elemente eingefügt. Dabei musste
man keinen Knotenpunktschnitt machen. Beweisen Sie, dass der Baum schon am
Anfang mindestens 2000 Elemente beinhaltete.
3.11. Entwerfen Sie eine Datenstruktur für die folgende Aufgabe!
Natürliche Zahlen sollen gespeichert werden. Eine Zahl kann auch mehrmals vorkommen. Operationen:
INSERT( ):
DELETE( ):
DELETEALL( ):
NUMBER( ):
ELEMENT( & ):
ein neues Exemplar von soll gespeichert werden
ein Exemplar von soll gelöscht werden
alle Exemplare von sollen gelöscht werden
gibt die Anzahl der Exemplare von
gibt das & -grösste Element
Die Anzahl der verschiedenen Elemente sei . (Beispiel: sind die gespeicherten
Elemente 1, 1, 3, 3, 3, 8, dann ist , NUMBER(1)=2
und ELEMENT(4)=3.)
10
Alle Operationen sollen einen Zeitbedarf von 7 2 haben.
3.12. Aus den ganzen Zahlen & 68& 6<:;:;:<6 & wird mit dem üblichen Algorithmus
ein AVL-Baum gebildet. (Die nächste Zahl wird immer eingefügt und, falls nötig, eine Drehung wird durchgeführt.) Beweise: beim Einfügen von mindestens
0
2 Zahlen ist keine Drehung nötig!
4
Hashing
4.1. Mit offener Addressierung wurden die Rekorden in einer Matrix der Grösse
6
0
mit Hilfe der '
7
& 2 & 7
Hash-Funktion gespeichert. Die Schlüssel
kommen wie folgt: '
6896 '76 ;6 96 '6; 6 '6 . Wie sieht die Matrix am Ende
aus, mit
1. linearem Sondieren?
2. quadratischem Sondieren?
4.2. In der Matrix ! $ <( wurden Elemente auf den ersten Plätzen
mit Hilfe einer unbekannten Hash-Funktion gespeichert so, dass die Plätze mit
0
Index 2 frei sind. Was ist die maximale Anzahl der Kollisionen mit
1. linearem sondieren?
2. quadratischem Sondieren?
0
4.3. Warum ist & 2$ der Hashtabelle ist 7.)
&'
0 72 keine geeignete Hashfunktion? (Die Grösse
4.4. Die Elemente 6 6<:;:;:<6 6 werden in einer Hashtabelle der Grösse
gespeichert; lineares Sondieren wird benutzt.
Beim Einfügen der ersten & Ele
mente ( & ) gab es insgesamt Kollisionen. Wieviele Kollisionen wird
es beim Einfügen von im schlimmsten Fall geben?
5
Datenkomprimierung
5.1. Kodiere das Wort MISSISSIPPIT mit Huffman-Kodierung! Wieviel wurde
im Vergleich zu dem Uniform-Code erspart? Kodiere das Wort auch mit LZWVerfahren!
5.2. Für die Häufigkeiten sind zwei optimale Kodierungen
bekannt: '6;'6<7'6;7 und '6'76;96;7 . Wieviel ist 6 6;6 , falls ?
5.3. Sei :<:;: und . Man nehme an, dass zur Verteilung
6;:;:;:=6 6 ein optimaler Huffman-Code bekannt ist. Füge ein bzw.
"
!
!
$
nach dem Codewort von ! Beweise, dass die so erhaltene Codemenge
#
%6 Verteilung optimal ist!
für die 6<:;:;:<%6 #
: ( die Häufigkeiten der Buchstaben von einem
5.4. Seien & :;:<'
(*
& ) ) elementigen Alphabet in einem Text. Man nehme an, dass in einer
optimalen Huffman-Codemenge alle Folgen der Länge & vorkommen. Was
kann der höchste Wert von sein?
7
5
5.5. Man kodiere einen Text über das Alphabet 6;? sowohl mit HuffmanKodierung als auch mit LZW-Kodierung. Im LZW-Wörterbuch seien alle Codes
-Bit lang. Gibt es einen Text, dessen LZW-Code kürzer ist?
5.6. Ein Text besteht aus Buchstaben. Was ist die minimale Anzahl der
Code-Wörter, die zur LZW-Kodierung nötig sind?
5.7. Die 6;76896 96 6 6 968 Folge ist der Lempel-Ziv-Welch Code eines Texts, der
ausschliesslich aus und Symbolen besteht. Das Wörterbuch enthält am Anfang
die Einträge und . Dekodiere das Wort!
5.8. Seien & :;:<:'( die Häufigkeiten der Buchstaben von einem
( &*) ) elementigen Alphabet in einem Text. Man nehme an, dass in einer
optimalen Huffman-Codemenge alle Folgen der Länge & vorkommen. Was
kann der höchste Wert von sein?
6
Graphentheoretische Algorithmen
0
6.1. Der schlichte gerichtete Graph 6"2 ist mit seiner Adjazenzmatrix
0
gegeben. Ein Knotenpunkt heisst Superquelle, falls 0 0 '2 $ 6 2
aber
6 92
. Gebe einen effizienten Algorithmus, der die
Superquelle findet (falls eine beinhaltet).
6.2. Zeige, dass BFS und DFS genauso implementiert werden können, mit dem
einzigen Unterschied, dass BFS eine FIFO-Liste und DFS eine LIFO-Liste verwendet.
6.3. sei ein binärer Baum, dessen Kanten von der Wurzel hinweg gerichtet
sind. Der Baum wird ausgehend aus der Wurzel mit der Tiefensuche traversiert.
Falls ein Knotenpunkt zwei Söhne hat, wird immer zuerst der linke Sohn besucht.
Beweise: die Sortierung der Knotenpunkte mit wachsender Tiefennummer entspricht der Preorder-Reihenfolge. Die Sortierung mit wachsender Abschlussnummer entspricht der Postorder-Reihenfolge.
beliebig. Beweise, dass es einen DAG mit 6.4. Sei , Knotenpunkten und Kanten gibt.
6.5. Gebe einen effizienten Algorithmus, der aus den Adjazenzlisten die „umgekehrten” Adjazenzlisten konstruiert! (Die umgekehrte Adjazenzliste beinhaltet
jene Kanten, die in den Knotenpunkt eingehen.)
6.6. Beweise: die Reihenfolge, in der der gelernte Algorithmus die starken Komponenten ausgibt, entspricht einer topologischen Ordnung des reduzierten Graphen.
8
6.7. Beweise: die Methode von Borůvka benötigt höchstens 7
Iterationen.
6.8. Ein Fluss in einem Netzwerk ist ein blockierender Fluss, falls jeder 0
0
Weg eine gesättigte Kante (d.h.:
2 2 ) beinhaltet. Beweise: jeder maximale
Fluss ist ein blockierender Fluss, aber umgekehrt gilt das nicht.
0 6.9. Gegeben ist der gerichtete Graph 6 2 mit positiven Gewichten an
0
den Kanten sowie der Knotenpunkt . Gebe einen Algorithmus mit
2
Zeitbedarf, der die Anzahl der kürzesten Wege für alle liefert.
6.10. Gebe einen effizienten Algorithmus, der einen längsten Weg in einem DAG
liefert!
6.11. Gebe einen effizienten Algorithmus, der die Knotenpunkte eines schlichten,
ungerichteten Graphen in zwei Teile spaltet so, dass mindestens die Hälfte der
Kanten zwischen den beiden Teilen laufen.
-Schachbretts stehen Pferde des Gegners.
6.12. Auf einigen Feldern eines Unser Pferd steht auf einem anderen Feld. Die gegnerischen Pferde machen keinen Schritt, nur wenn sie uns schlagen können. Gebe einen Algorithmus an, der
0
in
2 Zeit jene Felder bestimmt, die durch eine Reihe von Pferdschritten mit
unserem Pferd erreichbar sind, ohne durch den Gegner geschlagen zu werden!
0
6.13. 6 2 sei ein schlichter, zusammenhängender, ungerichteter Graph.
0
0 -0 0 2 2 . Der KnotenFür jeden Knotenpunkt sei 92 $ 6 2$
0
punkt ist ein Zentrum, falls 92 minimal ist. Gebe einen Algorithmus, der in
0 2>2 Zeit ein Zentrum findet!
0
6.14. 6 2 sei ein schlichter, zusammenhängender,
ungerichteter Graph.
5
ist ein Artikulationspunkt, falls ? nicht mehr zusammenhängend
10
ist. Gebe einen Algorithmus, der in
2 Zeit einen Punkt findet, der kein
Artikulationspunkt ist!
5
0
6 2 ein gerichteter Graph mit 6 46 6 6 6 ? . Die Kanten
6.15. Sei 0
0 0
und ihre Gewichte sind die folgenden: 6 2 , 6 2 , 46 2 ,
0
0
0
0 0
0
46 2 , 6 2 , 6 2 , 6 2 , 6 2 , 6 2 ,
0
0
0
-6 2 , -6 2 , -6 2 .
a) Bestimmen Sie die Länge des kürzesten Weges aus zu allen anderen Knotenpunkten mit der Methode von Dijkstra! Geben Sie die -Werte und die
Menge in jeder Iteration an!
b) Man möchte das Gewicht einer Kante mit 1 verkleinern, aber so, dass die
Entfernung der Knotenpunkte von Punkt nicht verändert wird. Welche
Kanten sind dazu geeignet?
9
6.16. Eine Bitfolge der Länge soll in Blöcke zerteilt werden, so dass jeder
Block mindestens 4 lang ist, und in jedem Block sollen die ersten zwei Bits identisch mit den letzten zwei Bits sein. Entwerfen Sie einen Algorithmus, der mit
0
2 Zeitbedarf entscheidet, ob so eine Zerteilung möglich ist!
6.17. Gegeben ist ein gerichteter Graph mit einer konservativen Gewichtfunktion
auf den Kanten (also kann das Gewicht mancher Kanten negativ sein, aber es gibt
10 2
keinen negativen gerichteten Kreis). Geben Sie einen Algorithmus, der in
Schritten einen (im gewichteten Sinne) kürzesten gerichteten Kreis liefert!
6.18. Der gerichtete Graph ist mit Adjazenzlisten gegeben. Die Kanten von
sind mit den Zahlen 76896<:;:;: 68& gewichtet. Der Wert eines Weges sei das Maximum der Gewichte seiner Kanten. Geben Sie einen Algorithmus, der den Wert des
0 Weges mit minimalem Wert zwischen zwei Knotenpunkten in
7 & 2 Schritten liefert!
7
Die Sprache NP
7.1. Nehmen wir an, dass es eine Methode gibt, die in einem Schritt entscheidet, ob ein Graph mit 3 Farben färbbar ist, oder nicht. Gebe einen Algorithmus an,
der als Eingabe einen Graphen erwartet und eine korrekte Färbung von mit 3
Farben in Polynomzeit ausgibt, falls mit 3 Farben färbbar ist!
7.2. Beweise, dass die folgende Sprache L in
ist!
5 0 0
6
und es gibt eine Lösung für
$
2 '
":: : 2 Achtung: die Eingabe enthält die Koeffizienten in binärer Darstellung!
7.3. Beweise, dass die folgende Sprache L in $
0
68& 2
ist!
ist ein bipartiter Graph und
hat genau & vollständige Paarungen
-vollständig ist!
$ ist ein ungerichteter0 Graph und besitzt
einen Weg, der aus 2A Kanten besteht Zeige, dass die folgende Sprache L in ist!
0
0 0 ist ein ungerichteter Graph, 6
$
2 6 2 und höchstens 2 Kanten führen zwischen und Welche der folgenden Funktionen $ gehört zur ?
9?
7.4. Zeige, dass die folgende Sprache L
7.5.
$
7.6.
10
)2
0
32$ 1.
0
32$ der kleinste echte Teiler von 2.
0
3.
32$ 7.7. Beweise, dass & -FARBE ( & 7.8. Zeige, dass BIN - PACKING
)
-vollständig ist!
, falls alle Gewichte grösser als sind!
7.9. Sei in einer X 3 C Aufgabe die Grösse der Grundmenge und die Anzahl der
10
3-elementigen Teilmengen . Zeige eine Boole-sche Formel der Länge 2 ,
die genau dann erfüllbar ist, falls X 3 C lösbar ist!
7.10. Man soll mit 3 Farben färben so, dass zu jedem Punkt eine verbotene
Farbe auch vorgeschrieben ist. Zeige, dass es in Polynomzeit entscheidbar ist, ob
eine solche Färbung existiert! (Hinweis: benutze, dass das Problem 2- KNF ist!)
7.11. Zeige, dass die folgende Sprache
$
0
68& 2
-vollständig ist!
ist ein ungerichteter Graph, &
: besitzt eine Teilmenge,
die aus min. & Punkten besteht und mit 2 Farben färbbar ist
Hinweis: reduziere das MAX - UNABHÄNGIG Problem darauf!
7.12. Beweise, dass PARTITION
RSP
$
0 ;6 : :: 6 TMSP
$
0 ;6 : :: 6 PARTITION
$
0 ;6 : :: 6 TMSP
RSP!
6<:: :6 & 2 wofür und es gibt 6468&
5
7.13. Beweise, dass MAXKREIS
WEG
7.15.
11
7.14. Beweise, dass HAMILTON
?
und
6
76;: :: 6
2 wofür und es gibt 5 76;: :: 6 ?
2 wofür -vollständig ist!
-vollständig ist!
5
und es gibt :
:
76<:: :6 ?
&
:
a) Beweise, dass die folgende Sprache in ist:
0
0
6 2 $
%2 6 hat einen spannenden Baum,
sind.
dessen Punkte mit Grad 1
b) Beweise, dass die folgende Sprache
-vollständig ist:
0
0
6 2 $
286 hat einen spannenden Baum,
dessen Punkte mit Grad 1 genau sind.
7.16. Beweise, dass die folgende Sprache
5 0
0
68& 2 $ %2$ &6 und 7.17. Beweise, dass
ben.
BIN - PACKING
ist in
-vollständig ist:
ist eine abdeckende Punktmenge. ?
, falls alle Gewichte die Form
ha-
7.18. Was ist die Komplexität des MAX - KLIKK Problems, falls jeder Punkt höch 0
stens Grad 7
2 hat?
7.19. Welche Funktionen sind in ?
0
a)
c)
2 Anzahl der Färbungen von mit 3 Farben
2 Liste der einfachen Wegen von 2 Liste der Dreicken von 0
b)
0
12
Lösungen
1
Einleitende Aufgaben
a) Sei 1.1.
. Dann gilt
also 10
7$
4
7
2 . Daraus folgt auch, dass 0
2
7
0
A2 .
0
0
also " 2 . Daraus folgt auch, dass " A 2 . Weiterhin,
0
10
0
2 , also A2 , 2 und 0
A2 .
b)
0
also . Daraus folgt, dass 2 , und auch
umgekehrt, also auch die Relationen und sind in beiden Richtungen
0
0
32 und 7 32 .
erfüllt. Aber 7 0
0
c) Sei 32 und 32 . Dann gilt
, und somit
0
10
0
2 , also auch 2 und 2 . Die anderen Relationen sind
nicht erfüllt.
7
1.2.
a) Zuerst wird das Gewicht von drei-drei Geldstücken verglichen. Falls
das eine leichter ist, ist das falsche Geldstück unter diesen drei Geldstücken,
sonst ist es unter den restlichen drei. Auf jeden Fall haben wir mit einem
Vergleich die Anzahl der möglichen falschen Geldstücken auf drei reduziert.
Von den drei möglichen falschen Geldstücken werden zwei verglichen. Falls
das eine leichter ist, ist es das falsche, sonst ist das dritte falsch. Also sind
zwei Vergleiche hinreichend. Man kann auch leicht einsehen, dass zwei Vergleiche auch notwendig sind.
13
b) Eine Lösung mit drei Vergleichen wird dargestellt. Zuerst wird die Anzahl
der möglichen falschen Geldstücke mit Hilfe von zwei Vergleichen auf zwei
reduziert, und im letzten Vergleich wird das falsche von diesen zwei gefunden. Nummerieren wir die Geldstücke von 1 bis 9.
Zuerst wird das Gewicht der Geldstücke 1, 2, 3 und 4, 5, 6 verglichen. Falls
sie gleich schwer sind, ist das falsche Geldstück unter den drei restlichen.
Dann werden zwei davon verglichen, z.B. Geldstück 7 und 8. Falls sie gleich
schwer sind, ist Geldstück 9 das falsche. Falls sie verschieden sind, dann
wissen wir, dass das falsche Geldstück entweder 7 oder 8 ist, also haben wir
unser erstes Ziel erreicht: nach zwei Vergleichen ist die Anzahl der möglichen falschen Geldstücke zwei.
Falls im ersten Vergleich z.B. 1, 2, 3 schwerer ist als 4, 5, 6, dann werden
danach die Geldstücke 1, 4, 7 und 2, 5, 8 verglichen. Hierbei wissen wir,
dass 7 und 8 gut sind.
Falls 1, 4, 7 und 2, 5, 8 gleich schwer sind, ist entweder 3 oder 6 falsch,
denn wir wissen aus dem ersten Vergleich, dass das falsche unter 1, 2, 3, 4,
5, 6 ist, und aus dem zweiten, dass es unter 3, 6, 9 ist, und der Durchschnitt
dieser Mengen ist 3, 6. Also haben wir die Anzahl der möglichen falschen
Geldstücken wieder mit zwei Vergleichen auf zwei reduziert.
Falls z.B. 2, 5, 8 schwerer sind, ist entweder 2 oder 4 falsch. Erklärung:
falls das falsche Geldstück leichter ist, ist es in 1, 4, 7 aber vorher war
4, 5, 6 leichter, also ist davon 4 das falsche. Falls aber das falsche Stück
schwerer ist, dann ist es in 2, 5, 8, und bei der ersten Messung war es unter
1, 2, 3, also ist 2 das falsche. Also sind nach zwei Vergleichen wieder nur
zwei Möglichkeiten übrig. Genauso, wenn bei dem zweiten Vergleich 1, 4,
7 schwerer sind, ist das falsche Element entweder 1 oder 5.
Aus zwei Elementen ist das falsche wie folgt zu bekommen: seien und
die ’verdächtigten’ Geldstücke. Dann ist und ein anderes Geldstück
zusammenzumessen, wobei wir wissen, dass nicht verfälscht ist. Wenn
und gleich schwer sind, ist das falsche, sonst .
1.3. Ein möglicher Algorithmus ist der folgende. Im Anfangsschritt wird das erste Element in den Speicher bewegt und seine Position aufgezeichnet. Die neue
Position dieses Elements wird mit ermittelt und in den Speicher geschrieben und
die zwei Elemente werden ausgetauscht. Falls sich in der neuen Position kein Element befunden hat, terminiert der Algorithmus.
Die neue Position eines Elements wird nach folgendem Prinzip festgelegt: falls
das Element sich in der ersten Teilarray befindet, wird seine Position mit & erhöht.
14
In dem anderen Fall wird die Position mit & erniedrigt. Der Prozess wird in Abbildung 1 veranschaulicht. Die neue Position des Elements wird also durch den
0 0
0
Formel
2 &'2 32 gegeben.
1
k k+1
n
n−k
1
n−k+1
n
Abbildung 1: Veranschaulichung der Methode
0
10
42 ArbeitsBei bewegten Elementen braucht die Methode 32 Schritte und
speicher, da in jedem Schritt sich genau ein Element und seine Position im Speicher befindet.
Sei der Anzahl der Schritte, nachdem der Algorithmus terminiert hat, . Da die
0
& 32 . Falls Methode in seiner Anfangsposition terminiert, gilt:
und & teilerfremd sind, gilt: , also werden genau Elemente ausgetauscht.
Falls und & nicht teilerfremd sind, muss der Algorithmus erweitert werden. Aus
0
0
der obigen Kongruenz folgt unmittelbar & . Dann gilt:
2 2 . Sei &-6 0
0
2 . Da und 6 2 , gilt es: , also muss die Methode
0
-, oder @68& 2 -mal ausgeführt werden, um alle Elemente auszutauschen. Damit es kein Element mehr als einmal bewegt wird, müssen die Anfangselemente
0
adequat ausgewählt werden. Falls die Methode für jede Position :;:<: 6 & 2
aufgerufen wird, ergibt es trivialerweise ein korrekter Vertausch des Teilarrays.
1.4. Sei eine Teilmenge mit einer – -Folge der Länge beschrieben. Falls das
Element in der Teilmenge vorkommt, steht in Position eine , sonst eine .
Die Folgen werden laut dem Gray-Code nacheinandergeordnet, was garantiert,
dass die Hamming-Distanz zwei nacheinanderkommenden Folgen 1 ist. So wird
die Kardinalität der Teilmengen, die die nacheinanderkommenden Folgen entsprechen ebenso um verschieden sein.
Die Gray-Codefolge der Länge wird wie folgt generiert. Die Codefolge der Länge besteht aus einer und einer :
15
0
Aus einer Codefolge der Länge ) A2 wird eine Codefolge der Länge generiert, indem unter der ursprünglichen Codefolge dieselbe in umgekehrter Reihenfolge aufgeschrieben wird. In einer zusätzlichen Spalte wird in allen Zeilen der
ursprünglichen Code die Zahl und in der umgekehrten die Zahl aufgeschrieben.
Der Zeitbedarf
für das Generieren der -ten Folge ist das Ausschreiben von zwei-
mal !
Folgen der Länge und ebenso zweimal das Ausschreiben von ,!
bits. Insgesamt werden also 3 bits ausgeschrieben. Ein Code kann in Schritten
10
,72
in eine Teilmengen konvertiert werden. Das ergibt einen Zeitbedarf von
Schritten. Die Optimalität dieser Schranke kann mit der Lösung folgender Rekur0
sion eingesehen werden. Bezeichne 2 den Zeitbedarf der Algorithmus für eine
Codefolge mit der Länge . Es gilt:
0
0
A 2 3
2 9 0
4 A2
1.5.
10
0
0
10
1 2
A2 heisst nach der Definition, dass
6> )
)
9 # 2 0
A2 :;:;:
:
32 0
Das heisst, die Funktion 32 ist beschränkt.
0
Wenn 32 die Zahl der Schritte eines Algorithmus bezeichnet, dann ist dieses
Problem mit konstanter Zahl von Schritten berechenbar (im schlechtesten Fall).
0 A2 heisst nach der Definition, dass
0
2
':
0
Das bedeutet, dass die Funktion 2 gegen strebt.
1.6. Wir definieren den Algorithmus mit vollständiger Induktion bezüglich der
Anzahl der Scheiben. Für eine Scheibe ist die Lösung trivial. Nun wird ein Verfahren gezeigt, das Scheiben auf eine andere Nadel umsetzt angenommen, daß
0
man 1 Scheiben umsetzen kann (sagen wir, in 1 A2 Schritten).
Nennen wir die Nadeln , und . Alle Scheiben befinden sich auf Nadel
das Ziel ist, alle auf zu packen. (Siehe Abbildung 2)
1. Setzen wir die obere Scheiben von
0
tionsannahme. ( A2 Schritte)
16
auf
,
. Das geht laut der Induk-
2. Setzen wir die zurückgebliebene -te Scheibe auf
3. Nun setzen wir die 1
Scheiben von
auf
. (Ein Schritt)
0
um. ( 1 A2 Schritte)
Den Zeitbedarf des Algorithmus bekommt man also mit der folgenden Rekursion:
0
0
0
0
32 A2 . Aus A2 ist 2 für alle weitere Werte von eindeutig bestimmt.
0
Wir behaupten: 3
2 .
Beweis mit vollständiger Induktion:
Anfangsschritt: Für ist die Formel korrekt.
0
0
0
A
2 2= A2 Induktionsschritt:
.
%' Also ist die Formel richtig. Nun soll gezeigt werden, dass man mindestens so
0
viele Schritte braucht. Sei die minimale Anzahl der nötigen Schritten 32 für 0
Scheiben. A2 .
Versuchen wir die Scheiben irgendwie auf eine andere Nadel umzusetzten. Betrachten wir den Augenblick, in dem wir die grösste Scheibe bewegen. Gebe es
mehrere solche Fälle, sollen wir den ersten betrachten. Die grösste Scheibe kann
nur auf eine leere Nadel umgesetzt werden, und nur dann, wenn sich keine weitere Scheiben über sie befinden (das folgt aus den Regeln), also müssen wir bereits
alle andere Scheiben auf die dritte Nadel umgesetzt haben. Dazu waren minde0
stens A2 Schritte erförderlich. Die Bewegung der grössten Scheibe nimmt
einen zusätzlichen Schritt in Anspruch. Schließlich muss man alle andere Scheiben von der dritten Nadel auf die Nadel umsetzten, auf die wir die grösste
0
Scheibe bereits umgesetzt haben. Dazu sind mindestens A2 Schritte nötig.
0
" A2' Schritte, um
Ein beliebiger Algorithmus benötigt also mindestens 0
0
0
A2 . Für 32
das Problem für Scheiben zu lösen. Also ist 2 haben wir die gleiche Rekursion erhalten, also ist die untere Schranke , . Mit
unserer Lösung wird das Problem in genau so vielen Schritten gelöst.
Nach der Sage darf der oberste Priester des Tempels nur jeweils eine Scheibe pro
Tag umsetzen. Das Ende der Zeit sei erreicht, wenn alle 64 Scheiben auf einer
dieser Nadeln wieder nach den Regeln aufgebaut werden. Das heißt, das unsere
Welt in 9 9 Tagen mit einem Donnerschlag samt Turm und
Tempel untergeht...
17
A
B
C
A
B
C
A
B
C
Abbildung 2: Türme von Hanoi, Veranschaulichung der Rekursion
2
Sortieren
2.1.
1. merge sort: Die wichtigsten Schritte der merge sort werden in einem
Pseudodebugger dargestellt. Als erstes wird der Routine rekursiv für die
immer kleinere (Teil)Arrays aufgerufen:
1: MSORT(4, 11, 9, 10, 5, 6, 8, 1, 2, 16)
2: MERGE( MSORT(4, 11, 9, 10, 5), MSORT(6, 8, 1, 2, 16) )
3: MERGE( MERGE( MSORT(4, 11, 9), MSORT(10, 5) ),
MERGE( MSORT(6, 8, 1), MSORT(2, 16) )
)
4: MERGE( MERGE( MERGE ( MSORT(4, 11), MSORT(9) ),
MERGE ( MSORT(10), MSORT(5) )
),
MERGE( MERGE ( MSORT(6, 8), MSORT(1) ),
MERGE ( MSORT(2), MSORT(16) )
)
)
5: MERGE( MERGE( MERGE ( MERGE( MSORT(4), MSORT(11) ), MSORT(9) )
MERGE ( MSORT(10), MSORT(5) )
),
MERGE( MERGE ( MERGE( MSORT(6), MSORT(8) ), MSORT(1) ),
MERGE ( MSORT(2), MSORT(16) )
)
)
Dann werden die Arrays “von unten nach oben” zusammengekämmt.
6: MERGE( MERGE( MERGE ( MERGE( 4, 11 ), 9 ),
MERGE ( 10, 5 )
),
MERGE( MERGE ( MERGE( 6, 8 ), 1 ),
18
MERGE ( 2, 16 )
)
)
7: MERGE( MERGE( MERGE ( (4, 11), 9 ),
(5, 10)
),
MERGE( MERGE ( (6, 8), 1 ),
(2, 16)
)
)
8: MERGE( MERGE( (4,
(5,
),
MERGE( (1,
(2,
)
)
9, 11),
10)
6, 8),
16)
9: MERGE( (4, 5, 9, 10, 11),
(1, 2, 6, 8, 16)
)
10: (1, 2, 4, 5, 6, 8, 9, 10, 11, 16)
Dabei wurde benutzt, dass die Funktion ihr Argument als Ergebnis liefert, wenn es mit einer Zahl aufgerufen wird.
2. quick sort: Die wichtigsten Schritte der quick sort werden in einem Pseudodebugger dargestellt.
Errichten der ersten Partition mit :
1:
1:
2:
3:
4:
5:
QUICKSORT(
PARTITION(
PARTITION(
PARTITION(
PARTITION(
QUICKSORT(
(4,
(4,
(4,
(4,
(4,
(4,
11, 9, 10, 5, 6, 8, 1, 2, 16) )
11, 9, 10, 5, 6, 8, 1, 2, 16), (5))
2, 9, 10, 5, 6, 8, 1, 11, 16), (5))
2, 1, 10, 5, 6, 8, 9, 11, 16), (5))
2, 1, 5, 10, 6, 8, 9, 11, 16), (5))
2, 1) ), 5, QUICKSORT ( (10, 6, 8, 9, 11, 16) )
Nach dem Errichten der ersten Partition läuft die Sortierung folgendermassen weiter:
19
6: QUICKSORT( PARTITION( (4, 2, 1), (2) ),
5,
PARTITION( (10, 6, 8, 9, 11, 16), (9) )
)
Errichten der Partition in .!/%$, ( mit :
7: PARTITION( (4, 2, 1), (2) )
8: PARTITION( (1, 2, 4), (2) )
9: QUICKSORT( 1 ), 2, QUICKSORT(4)
Errichten der Partition in .! $ ( mit :
10:
11:
12:
13:
11, 16), (9) )
11, 16), (9) )
11, 16), (9) )
QUICKSORT( (10, 11, 16) )
PARTITION(
PARTITION(
PARTITION(
QUICKSORT(
(10, 6, 8, 9,
(9, 6, 8, 10,
(6, 8, 9, 10,
(6, 8) ) , 9,
ihr Argument als
Mit Berücksichtigung, dass die Funktion
Ergebnis liefert, falls sie mit einer Zahl aufgerufen wird und nach der Sor0
0
tieren der Arrays '6 72 und 96;776; ,2 ist das Ergebnis:
(1, 2, 4, 5, 6, 8, 9, 10, 11, 16)
3. heap sort: Es wird ein binäres Heap konstruiert und mit heap sort sortiert.
Die Schritte werden in einem Pseudodebugger dargestellt.
1:
2:
3:
4:
5:
6:
7:
(4,
(4,
(4,
(4,
(4,
(1,
(1,
11, 9, 10, 5, 6, 8, 1, 2,
11, 9, 1, 5, 6, 8, 10, 2,
11, 6, 1, 5, 9, 8, 10, 2,
1, 6, 11, 5, 9, 8, 10, 2,
1, 6, 2, 5, 9, 8, 10, 11,
4, 6, 2, 5, 9, 8, 10, 11,
2, 6, 4, 5, 9, 8, 10, 11,
16)
16)
16)
16)
16)
16)
16)
//Sickern(A[4])
//Sickern(A[3])
//Sickern(A[2])
//Sickern(A[1])
Wie bekannt, wird ein Heap aus einer ungeordneter Array von Elementen
konstruiert, indem die Funktion Sickern auf alle Elemente von "! -( bis .!/<(
aufgerufen wird. Hier wurden nur die Aufrufe dargestellt, die tatsächlich
Elemente bewegt haben.
Nachdem die Konstruktion fertig ist, entspricht der Array ein binäres Heap.
20
Falls diese Repräsentation adequat ist, ist die Sortieraufgabe erledigt, sonst
kann die sortierte Liste mit zehnmaliger Anwendung der Heap-operation
removeMin bekommen werden.
Die sortierte Liste: 1, 2, 4, 5, 6, 8, 9, 10, 11, 16
2.2. Für das Finden des kleinsten Elementes unter Elemente sind Vergleiche nötig. Zuerst werden zwei beliebige Elemente verglichen und das grössere
wird verworfen. Danach wird das kleinere mit einer beliebigen Element aus der
Menge der restlichen Elemente verglichen. Dieses Verfahren wird wiederholt bis
das kleinste Element gefunden ist.
Weniger als Vergleiche reichen nicht aus,was folgendermassen eingesehen werden kann: Sei das Problem mit einer Graph dargestellt. Die Knotenpunkte repräsentieren die einzelnen Elemente und eine Kante zwischen zwei Knotenpunkte läuft, wenn wir die Elemente verglichen haben, also wenn wir wissen, welches der Elementen das kleinere ist. Falls dieser Graph nicht zusammenhängend
ist, gibt es mindestens zwei Mengen von Elemente, und , wo über keinen
0 6
%6
2 Paar bewusst ist, ob oder das kleinere ist. Deshalb ist es
nicht zu entscheiden, ob das kleinste Element in der Menge oder in ist. Ein
Graph mit Punkte braucht mindestens Kanten, damit er zusammenhängend wird. Also reichen weniger Vergleiche nicht aus.
Für das zweitkleinste unter Elementen zu finden werden Vergleiche in mehrere
Iterationen durchgeführt. In der ersten werden aus den Elementen Paare gebildet
und verglichen. In der nächsten Iteration werden die Paare aus den kleineren Elementen gebildet. Somit sind :;:;:) , insgesamt also Vergleiche
nötig, um das kleinste Element zu finden. Diese Vergleichsiterationen können als
Etagen eines Baumes geschaut werden, in dem die Knotenpunkte die verglichene Elemente repräsentieren und Kanten zwischen den verglichenen Elemente der
jeweiligen Iteration und dem kleineren Element (der auch in der nächsten Iteration teilnimmt) laufen (s. Abb. 3). In diesem Baum ist das gesuchte zweitkleinste
Element das kleinste unter denen, die mit dem Minimum verglichen sind, . Da der
Baum insgesamt 7 Etagen hat, wird das kleinste unter 7 Elemen
te gesucht, was 7 Vergleiche erfordert. Das ergibt einen Zeitbedarf von
9 Vergleiche. Das Auswählen des & -kleinsten Elementes geschieht
nach dem Prinzip der Bürgerwahl, das in dem Vorlesungsskript [Vorlesungsskript]
ausführlich beschrieben ist.
2.3. Wegen der Heap-Eigenschaft ist es garantiert, dass sich das zehntkleinste
Element nicht tiefer als der -te Etage in dem Heap befindet. Der Zeitbedarf einer Methode, die die ersten Etagen des Heaps kopiert und in diesem kopierten
Heap das zehntkleinste Element findet, ist unabhängig von der Grösse des ori
ginalen Heaps, da der Heap-Operation mit der Tiefe des kopierten
21
Abbildung 3: für Aufgabe 2.2.
10
0
Heaps proportional ist. Somit wird das gesuchte Element in ,2 A2
Schritte gefunden, indem wir das Heap-Operation zehnmal auf das
kopierte Heap anwenden.
0
2.4. Sei der Zeitbedarf für das Aufbauen des Heaps 2 . Da das Finden des
Minimums unter Elmenten laut 2.2. Vergleiche benötigt und das kleinste
0
0
Element eines Heaps in einem Schritt gefunden werden kann, gilt 32 A2 0
0
0
3
2
2 2.
10
2.5. Es wird bewiesen, dass der Zeitbedarf der effizientesten Algorithmen 7 3
2
0
und 7 32 ist.
Sei der Vergleich auf drei beliebige Elemente angewendet; das mittlere Element
ist weder das Maximum noch das Minimum. Dieses Element wird weggeworfen
und die zwei anderen werden mit einem neuen verglichen. Diese Prozedur findet
die beiden Extrema in Schritte, allerdings ohne den Kenntnis, welches von
denen das Maximum oder das Minimum sei. Eines der beiden wird willkürlich
ausgewählt und in den weiteren Vergleichen immer als drittes Element festgelegt.
Da dieses ein Extremum ist, wird das Ergebnis einer Vergleich zwei beliebiger
anderen Elementen und dieses Elements dasselbe Ergebnis liefern, als ein “konventioneller” Vergleich der zwei Elemente. Abhängig davon, ob das Maximum
oder das Minimum als drittes Element festgelegt wurde, wird das mittlere Element das grössere/kleinere der beiden sein.
0
Im weiteren werden die bekannten Sortierungsmethoden – mit Zeitschranke 7 3
2
– angewendet, um eine wachsende/fallende Sortierung zu generieren. Somit hat
10
0
die Methode eine obere Zeitschranke 7 2 7 2 .
Für den Beweis der unteren Zeitschranke sei angenommen, dass es einen Algo10
rithmus schneller als 7 32 gibt, der auf solche Vergleiche basiert. In diesem
Fall könnten aber die Sortierungen, die Vergleiche zweier Elementen verwenden,
auch schneller sein, weil die Frage “Welches ist das mittlere von drei Elementen?”
10
mit
A2 solchen Vergleichen beantwortet werden kann.
22
Da aber das schnellste Sortierverfahren, das auf Vergleiche basiert, eine Zeit0
schranke 7 2 hat, muss auch der Zeitbedarf aller Sortierungen, die auf sol0
che Vergleiche dreier Elemente basieren, auch 7 32 sein.
3
Suchbäume
3.1. Es kann leicht gezeigt werden, dass das inorder Durchfahren die Rekorde
eines binären Suchbäumes eben in Grössenordnung zurückgibt. Die Kost dieser
0
Methode für Bäume mit Punkten ist 2 . Also traversieren wir beide Bäume;
damit bekommen wir die Elemente der zwei Bäumen in Grössenordnung. Dann
kämen wir die Ergebnisse der zwei Durchläufen zusammen! Das kann auch in
0
0
& 2 gemacht werden, also die Kost des Verfahrens ist & 2 .
3.2. Wir lösen die Aufgabe mit vollständiger Induktion. Sei die Anzahl der
Knotenpunkten im binären Baum . Es ist trivial, dass in dem Fall die
Differenz der Anzahl der Blätter und der Anzahl der Knotenpunkten mit Grad eins ist. Nehmen wir an, dass die Eigenschaft für jede & erfüllt ist. Betrachten
wir $ ist! Zwei mögliche Fällen sollen
, wo ein Blatt des Bäumes
behandelt werden:
1. war adjazent zu einem Punkt mit Gradzahl 1 in . Mit der Entfernung
von bleibt die Anzahl der Blätter und der Knotenpunkten mit Grad invariant, nämlich statt wird ein Blatt sein.
2. war adjazent zu einem Punkt mit Gradzahl 2 in . Die Entfernung von dekrementiert sowohl die Anzahl der Blätter als auch die Anzahl der Knotenpunkten mit Grad mit .
Also die Differenz der Anzahl der Blätter und der Anzahl der Knotenpunkten mit
Grad ist invariant, und wegen der Induktionsannahme erfüllt die Eigenschaft.
Daraus folgt, dass sie auch für gelten muss.
3.3. Sei die Wurzel des Bäumes. Da die Suchbaumeigenschaft erfüllt und
der Baum vollständig ist, folgt, dass # Elemente
kleiner und ! Elemente grösser sind als . Deswegen kann nur 7! oder # sein.
1. ! , dann das fehlende Element ist im Intervall !#6;:;:;:=68# ( .
0
Die Aufgabe ist das fehlende Element aus diesem Intervall in & 92 zu
finden.
23
1)
2)
Abbildung 4: Die zwei möglichen Fälle in Aufgabe 3.2.
2. # , dann das fehlende Element ist im Intervall !* #
7
6;:<:;:<68 ( .
0
Die Aufgabe ist das fehlende Element aus diesem Intervall in
92 zu
finden.
Wir benutzen das selbe Entscheidungsverfahren rekursiv für die so ausgewählten Teilbäume mit dem dazugehörigen Suchintervall. In der letzten Iteration des
Algorithmus erhält man ein zweielementiges Intervall und ein einziges Blatt als
Teilbaum; das Ergebnis ist die Zahl, die nicht zu diesem Blatt gehört. Das Ver0
fahren besucht jede Etage des Bäumes genau einmal, das heisst, die Kost ist 2
00
A2< A2 (ein vollständiger binärer Baum mit Elemente besitzt 7
Etagen). Die Optimalität des Algorithmus kann mit dem Gegner-Prinzip gezeigt
werden.
3.4. Bezeichne & die Anzahl der Punkten im binären Baum. Setzen wir vollständige Induktion ein! Für & ist die Behauptung trivial. Nehmen wir an, dass alle
solche Bäume mit weniger als & Punkten vollständig sind. Sei ein binärer Baum,
der die Eigenschaft erfüllt und & Knotenpunkten hat. Dann der linke Unterbaum
und der rechte Unterbaum sind wegen der Induktionsbedingung vollständig.Falls
die Unterbäume die Höhe und haben, gilt es für :
#
was bedeutet, dass
7
!
7
auch für & vollständig ist.
24
0
A2 3.5. Es ist bekannt, dass in einem 2-3 Baum alle Wege von der Wurzel zu den
Blättern gleich lang sind. Sei der Schlüssel in der Wurzel ! *>( ! Es
ist klar, dass alle Elementen von !#76<:;:;: 6; ( enthält. Da ein Knotenpunkt mindestens zwei Söhne hat, kann dieser Teilbaum höchstens Etagen haben. Es folgt,
dass die Teilbäume gehörend zu und " auch höchstens 5 Etagen hoch sein
können. In diesen Bäumen müssen wir 162 Elemente speichern, also beinhaltet
der grössere Teilbaum mindestens 81 Elemente. Aber in einem 2-3 Baum können
höchstens 81 Elemente in 5 Etagen aufgenommen werden; das heisst beide Teilbäume 81-81 Elemente speichern, und zwar so, dass jeder innere Knotenpunkt die
Gradzahl hat. Deswegen ist ' .
0
3.6. Nehmen wir an, dass jeder Knotenpunkt die Höhe seines Unterbäumes 2 beinhaltet.
0
Bezeichne ausserdem 2 die Höhe eines AVL-Bäumes! Es verletzt die Allge0
0 meinheit nicht, falls wir annehmen, dass 2 2 . Die Schritte des Algo
rithmus sind die folgende (siehe Abbildung 5):
(sei das ), dadurch
1. Wir finden und löschen das kleinste Element von
erhalten wir den Baum .
2. Angefangen von dem Wurzel von und als nächster Kandidat immer den
Rechtssohn des aktuellen Knotenpunktes betrachtet finden wir den ersten
0
0
2 2 oder befriedigt.
Knotenpunkt , der 3. Vertauschen wir mit . Sei der Rechtsbaum von und der Linksbaum
von der Unterbaum von .
Der Baum, den wir so erhalten haben erfüllt offensichtlich gleichzeitig die Suchbaumund die AVL-Eigenschaft. Bezeichne die Gesamtzahl der Elementen in den
0
zwei Bäumen! Da beide Bäumen 7 32 hoch sind, ist die Kost der Methode
0
7 32 .
3.7. Konstruieren wir den Baum! Das Paar mit minimaler zweiter Koordinate
muss in der Wurzel stehen, weil die zweiten Koordinaten die Heap-Eigenschaft
0
erfüllen und alle Koordinaten verschieden sind. Sei die Wurzel 6 2 . Da
die ersten Koordinaten die Suchbaum-Eigenschaft erfüllen müssen, gehören die
Paaren, deren erste Koordinate ist dem linken Teilbaum, die anderen dem
0
rechten Teilbaum. Die selbe Bedachten gelten für die Wurzeln von & 92 und
0
92 , deswegen sind die auch eindeutig bestimmt. Es folgt, dass in jedem
Schritt, als wir die Wurzel eines Teilbäumes auf den aufeinanderfolgenden Etagen
bestimmen, genau ein Koordinatenpaar die vordefinierten Bedingungen erfüllt.
Die Konstruktion zeigt, dass genau ein solcher binärer Baum existiert.
25
s
x
x
S1
S3
Abbildung 5: Wirkungsweise des Algorithmus in Aufgabe 3.6.
3.8. Die Aufgabe kann mit dem Verwenden des bekannten Einfügen-Algorithmus
gelöst werden. Die Zahlen in der gegebenen Reihenfolge eingefügt erhält man den
Baum auf Abbildung 6.
Abbildung 6: Der AVL-Baum in Aufgabe 3.8.
0 3.9. Es soll bemerkt werden, dass zu jedem Punkt 6
2 höchstens A
solche verscheidene Nachbaren existieren können, deren Entfernung von kleiner oder gleich ist (es folgt davon, dass die Koordinaten nur ganzzählige Werte
0
aufnehmen dürfen). Für jeden Punkt sollen wir in 7 2 entscheiden, ob
mindestens eine der A Plätzen, die genügend nahe zu sind, von einem anderen
Punkt besetzt ist. Das kann gemacht werden,
falls wir vor der0 Suche aus den Koor0
dinatenpaaren einen Suchbaum in 32 Schritte mit 7 2 Etagen bilden
(die Punkten können z.B. lexikographisch geordnet werden und der Suchbaum
kann ein AVL- oder - Baum sein).
3.10. Da es keinen Knotenpunktschnitt geschah, können wir sicher sein, dass
nur innere Knotenpunkte an der “vorletzten Stufe” (d.h. deren Zeiger auf Rekordelemente zeigen) durch das Einfügen modifiziert wurden. Weiterhin können wir
sehen, dass die einzige, unter diesen Bedingungen erlaubte Insert-Operation das
Zufügen eines dritten Rekordes zu einem inneren Knotenpunkt mit zwei Söhnen
26
ist. Nach dem Einfügen wird dieser Knotenpunkt schon Söhne haben, müssen
also die anderen Einfügen bei einem anderen Knotenpunkt geschehen. 1000 Elemente einzufügen brauchen wir mindestens 1000, nicht zu trennende Knoten an
der vorletzten Stufe – natürlich sind mit drei Elemente “gesättigten” Knoten auch
erlaubt. Diese sich selbst speichern schon vor der Operation 2000 Elemente.
3.11.
Die Datenstruktur: Man nehme einen Knotenpunkt in
einem AVL-Baum zu jedem verschiedenen Element
auf. In den Knotenpunkten speichert man zusätzlich
die Anzahl der Elemente mit diesem Wert (im Weiteren count genannt). Ausserdem wird die Anzahl aller Elemente des Teilbäumes (inklusive Wurzel), dessen Wurzel der Knotenpunkt selbst ist, aufgenommen
(hier sumcnt genannt). Das ist in unserem Fall genug, da wir Zahlen und keine zusammengesetzte Datenstrukturen speichern wollen. (Siehe Abbildung 7)
Left
Left
Left
Node’s
Key
Count
SumCnt
Right
Node’s
Key
Count
SumCnt
Left
Node’s
Key
Count
SumCnt
Right
Right
Left
Node’s
Key
Count
SumCnt
Node’s
Key
Count
SumCnt
Right
struct mynode {
int value;
int count;
int sumcnt;
mynode *left;
mynode *right;
}
Left
Node’s
Key
Count
SumCnt
Right
Right
Left
Node’s
Key
Count
SumCnt
Right
Abbildung 7: Ein spezieller AVL-Baum
Die Operationen benutzen oder erweitern die bei den AVL-Bäumen gelernte Operationen. Es folgt eine kurze Beschreibung der Verwirklichung der Operationen:
INSERT(i): Der Knotenpunkt gehörend zu wird gesucht; falls gefunden count++;
falls nicht, dann wird ein neuer Knotenpunkt erstellt. Bei10
der Suche wird sumcnt
von jedem besuchten Knotenpunkt mit 1 inkrementiert. 7 2
DELETE(i): Zuerst wird überprüft, ob das Element in dem Baum überhaupt
vorkommt. Falls NUMBER(i) positiv ist, gehen wir wie folgt um: der Knoten
punkt gehörend zu wird gesucht. Bei der Suche wird sumcnt von jedem be27
suchten Knotenpunkt mit dekrementiert. Wenn gefunden, count--. Im Fall
0
count==0 wird der Knotenpunkt gelöscht. 7 2
DELETEALL(i): Der Knotenpunkt gehörend zu wird gesucht. Bei der Suche
wird sumcnt von jedem besuchten Knotenpunkt um NUMBER(i) dekremen10
tiert. Der Knotenpunkt wird gelöscht. 2
NUMBER(i): Der Knotenpunkt gehörend zu10 wird gesucht; falls er gefunden
wurde, return count, sonst return 0. 7 2
ELEMENT(k): Der entsprechende Knotenpunkt wird mit der folgenden Funktion
gesucht:
int ELEMENT(int k) {
mynode *this = &root;
if (this->sumcnt < k) return -1;
while (true) {
if (this->left->sumcnt >= k)
this = this->left
else if (this->left->sumcnt + this->count >= k)
return this->value
else {
this = this->right;
k-=this->left->sumcnt + this->count;
}
}
}
Grundidee:
Wir wissen über jeden Teilbaum, wie viele Elemente er beinhaltet (sumcnt).
Wenn k kleiner ist als sumcnt des linken Unterbäumes eines Knotenpunktes,
müssen wir im linken Unterbaum weitersuchen. Ist k größer als sumcnt des
linken Teilbaumes aber nur maximal um count größer, haben wir den gesuchten
Wert gefunden.
Sonst müssen wir in dem rechten Unterbaum weitersuchen, genauer gesagt das
k-left->sumcnt-count-te Element des rechten Unterbaumes suchen.
0
7
2
3.12. Ein AVL-Baum hat die Eigenschaft, dass für jeden Punkt des Baumes die
Längen ihrer Unterbäume höchstens um unterscheiden. Falls während der Aufbau des Baumes diese Eigenschaft verletzt wird, kann sie mit Drehungen widerhergestellt werden.
28
Betrachten wir das Einfügen eines Elements in den Baum. Ein Einfügen wird als
eine Eröffnung einer neuen Etage bezeichnet, falls der ganze Baum vor dem Ein
fügen , nach dem Einfügen Etagen hat.
Wird ein Element in dem Unterbaum eines Punktes eingefügt, der eine kürzere
Länge als der andere Unterbaum hat, dann wird keine neue Etage eröffnet. Also
ist auf diese Weise in dem Baum keine neue Etage zu eröffnen. Eine neue Etage
ist nur so anzufangen, wenn vor dem Einfügen des eröffnenden Elements alle Unterbäume die gleiche Länge haben. Dann ist nach dem Einfügen keine Drehung
erforderlich. Also ist der erste Punkt auf jede Etage während der Konstruktion
ohne Drehung eingefügt worden. Es gibt 7 Etagen, also gibt es mindestens
0
2 solche Schritte während der Konstruktion, bei denen nicht gedreht wird.
4
Hashing
4.1.
1. mit linearem Sondieren:
!*96
_6
'6
96
6
6
'6
_6
96
'76
(
_6
'76
(
2. mit quadratischem Sondieren:
!*96
'6
96
96
6
96
'6
_6
0
4.2. a) mit linearem Sondieren: Es sei &2 + . Ist der Platz + noch frei,
dann können wir dieses Element problemlos speichern. Man sieht auch, dass keine
Schlüssel-Kollisionen, die diesen Platz auffüllen könnten, existieren mit linearem
0 Sondieren; gebe es eine solche Kollision, dann wäre der Platz A2 nicht frei.
0
Die Stelle kann zweierlei eingefüllt werden: entweder mit & 2 0
– ist noch frei, keine Kollision, oder mit &=2 – ist schon
besetzt und ist frei, eine Kollision. kann nicht schon eingefüllt sein; es
würde uns zwingen, die Schlüssel auf den -ten Platz zu stellen, was nicht erlaubt
ist. Daraus folgt, dass ein Elementpaar höchstens eine Kollision hervorrufen kann;
für Elemente bedeutet das höchstens Kollisionen.
b) mit dem selben Gedankenfolge kann es gezeigt werden, dass die maximale
Anzahl der Kollisionen ist.
0
4.3. Eine Hashfunktion ist gut, falls die & 2 Werte in allen Restklassen ungefähr
0
im gleichen Verhältnis vorkommen. Dazu ist es notwendig, dass die & 2 Werte
ein vollständiges Restklassensystem bilden (modulo Hashtabellengrösse).
29
Bei dieser Hashfunktion kommen aber einige Restklassen nie vor. Es is bekannt,
0
0
dass & 72 nur von & 72 abhängt.
&
&9
0 7
2
0 72
0 72 kommen nicht vor.
Das heisst, die Restklassen 96 und 4.4. Beim Einfügen des Elements wird es höchstens & Kollisionen geben,
denn es ausser diesem Element nur & andere in der Hashtabelle sind und lineares
Sondieren benutzt wird (wegen dem linearen Sondieren ist es nicht möglich, dass
es mehr als eine Kollision mit demselben Element gibt, falls es noch freie Plätze
mindestens
vorhanden sind). Da ) & , gibt es beim Ablegen des Elements noch einen freien Platz, die wegen dem linearen Sondieren höchstens nach & Kollisionen erreicht wird.
& Kollisionen können tatsächlich vorkommen, zum Beispiel, wenn die Hashfunk tion
immer dieselbe Addresse für die Elemente gibt. In diesem Fall wird es Kollisionen bei dem Einfügen der ersten & Elemente geben, also wird diese
Voraussetzung auch erfüllt.
5
Datenkomprimierung
5.1. Die Häufigkeit der einzigen Buchstaben:
Eine optimale Kodierung ist:
7
7
'
In den Uniform-Koden sind alle Kodwörter gleich lang, und weil wir einen Wort
von verschiedenen Buchstaben kodieren müssen, sind alle Kodwörter Bit lang.
Dass heisst die Länge der Uniform-Kode A ist. Die Länge des Wortes
in der Huffman-Kode ist , also Bit wurde
erspart. Bei der LZW Kodierung erhält man das folgende Wörterbuch:
Das kodierte Wort ist
30
7
A
4
Abbildung 8: Die zu den optimalen Kodierungen gehörende Huffman-Bäume in
Aufgabe 5.2.
5.2. Konstruieren wir die zwei Huffman-Bäume (siehe Abbildung 8)! Man sieht
leicht, dass gelten muss,
sonst wäre die Kodierung eindeutig. Es ist
bekannt, dass , also . ist ein möglicher
Wert von
; damit ist
, eine Lösung.
, , Es gilt auch, dass andere Lösungen existieren
nicht.
Nehmen
wir
indirekt
an, dass
! Dann wäre aber und . Das würde bedeuten,
dass @$
, was ein Widerspruch ist.
$ ist ein optimaler Huffman-Code be5.3. Zur Verteilung 6<:;:;:<6%
6%
# #
entsprechenden
kannt, und damit auch ein Huffman-Baum, der einen, ! gehörenden KoBlatt beinhaltet. Die Zufügung einer und einer zum !
dewort (mit dem Zweck, die zweite Verteilung zu kodieren) kann als die Beigabe
und eines Sohnes zum Knotenpunkt im Huffman-Baum
eines !
!
repräsentiert werden. Es soll gezeigt werden, dass der so erhaltene Baum jetzt
6 eine optimale Kodierung der Verteilung 6;:;:;:=6 beschreibt. Es ist aber
0
!
leicht: da :;:;: 72 , es existiert unbedingt ein Ablauf
!
des Huffman-Code generierenden Algorithmus, der im ersten Schritt und !
zussamenknüpft - und der danach gebliebener Baum entspricht den originalen,
also von hier ist der Algorithmus die vorgegebene Kodierung zu reproduzieren
fähig. Damit wurde ein Huffman-Baum zur modifizierten Codemenge gegeben.
5.4.
5.5. Sei der Text eine -elementige -Folge. Mit Huffman-Code sind zur Kodierung Bits benötigt. Mit LZW-Kodierung
kodieren wir in jedem Schritt mit mehr Charakter als bevor. Sei ! Wir suchen eine Länge, deren LZWCode schon günstiger ist, als die Huffman:
0
A2 ) 31
)
Also die LZW-Code z.B. einer 4 langen -Folge ist nur 7 A
Bit lang. Es sollte noch überprüft werden, ob 16 verschiedene Koden auf Bit
wirklich existieren, das kann aber leicht gesehen werden.
0
A2 5.6. Im 5.5. haben wir gesehen, dass zur Kodierung einer Elementigen Folge einer einzigen Buchstabe Code-Wörter genügend sind. Nach
dem Funktionsweise der Algorithmus ist es auch klar, dass eine -Lange Charakterfolge mit weniger
Code-Wörter
nicht kodiert werden kann. Es ist auch klar,
0
+ A2 . ) lange Charakterfolge einer Buchstabe
dass eine ( auch mit Code-Wörter beschreibbar ist. Da , braucht man
mindestens Code-Wörter.
5.7.
5.8.
6
Graphentheoretische Algorithmen
6.1. Der Ablauf des Algorithmus wird in zwei Phasen unterteilt. In der ersten
werden aus einer Menge der Superquelle-Kandidaten Knotenpunkte ausgeschlossen. So wird sie auf eine leere oder einelementige Menge reduziert und in dem
zweiten Fall der Kandidat überprüft, ob er wirklich eine Superquelle ist.
Erste Phase:
0
Initialisierung: Bezeichne die Menge
2 . In jedem Schritt wird ein Paar
0
0 6 =2
6 2 untersucht und gemäss den folgenden Regeln modifiziert:
0
0
1. falls 6 2
entfernt, da in
%2 , werden beide Knotenpunkte aus
diesem Fall weder noch Superquelle sein kann;
0
0
%2 , wird aus entfernt, da in diesem Fall ;
2. falls 6 2
0
0
3. falls A6 2
2 , wird aus
entfernt, da in diesem Fall keine
Superquelle sein kann.
32
Somit wird in maximal Schritten auf eine leere oder einelementige Menge reduziert. Falls leer ist, terminiert der Algorithmus und es gibt keine Superquelle. Falls es noch einen Superquelle-Kandidat gibt, wird die zweite Phase des
Algorithmus
ausgeführt:
5
0
0
0 Sei ? . Es wird die Existenz aller Kanten der Form 6 2 und 6 2
30
0
0
0
2 überprüft. Falls
6 2
%2 oder
6 2
%2 , also es gibt einen
Knotenpunkt , der aus nicht, oder, aus dem über eine Kante erreichbar
ist, terminiert der Algorithmus und es gibt keine Superquelle; sonst ist eine
Superquelle.
0
32 Schritte. Das ergibt eine Zeitschranke von
Beide Phasen terminieren in
0
32 für den Algorithmus.
6.2. Beide Algorithmen werden in Pseudokode dargestellt. Anschliessend wird
es erläutert, warum sie jeweils die entsprechende Suche realisieren.
List L = {};
Tree T = {};
choose starting vertex x;
search(x);
while (L != {})
{
^^IEdge (v,w) = List.get(L);
if w not yet visited
{
^^I^^I^^I
^^I^^I^^I
add (v,w) to T;
search(w);
}
}
search(Vertex v)
{
visit(v);
foreach Edge (v,w)
List.put(L, (v,w));
}
Der Algorithmus nimmt an, dass der als Eingabe gegebener Graph zusammenhängend, oder im Falle eines gerichteten Graphen stark zusammenhängend ist. In
dem Baum wird der traversierte Graph aufgebaut. In der Liste werden jene
noch nicht besuchte Kanten gespeichert, die zu einem besuchten Knotenpunkt inzident sind. Aus dieser Liste entnimmt der Algorithmus die nächste Kante.
33
Als Initialisierung wird ein beliebiger Knotenpunkt als Anfangspunkt gewählt,
und die Kanten, die zu inzident sind, werden in gespeichert.
0
In einem Schritt wird eine Kante von der Liste entfernt. Sei das die Kante -6 2 .
0
Falls noch nicht besucht worden ist, wird es zusammen mit 6 2 in den Baum
aufgenommen und alle Kanten, die zu inzident sind, werden in die Liste
eingefügt. Nach dem Ende der Suche wird der Graph ein BFS- oder DFS-Baum
des traversierten Graphes sein, da jeder Knotenpunkt genau einmal in aufgenommen wurde.
Das Unterschied zwischen der Breitsuche und der Tiefsuche liegt in der Realisation der Methoden List.get und List.put. In einer möglichen Realisation der
Breitsuche nimmt List.get die nächste Kante von dem Anfang der Liste und fügt
List.put Kanten an das Ende der Liste ein, also implementieren sie eine FIFOListe. Dementsprechend kann eine Tiefsuche durch eine LIFO-Liste mit derselben List.get Operation und eine List.put, die die Kanten an den Anfang der Liste
einfügt, realisiert werden.
Eine FIFO-Liste realisiert die Breitsuche wegen Folgendem: Wenn die Suche den
0
Knotenpunkt durch die Kante 6 2 besucht hat, werden danach sämtliche
andere Knotenpunkte, die zu benachbart sind, besucht und erst danach die zu
benachbarte Knotenpunkte, u.s.w. Zur Veranschaulichung wird ein Beispiel
der FIFO-Liste vor und nach dem Besuchen des Knotenpunktes gezeigt:
0
0
0
0
0
vor Besuch des Knotenpunktes : -6 2 6 6 286 6 2 6 -6 82:;:;: 6 2
nach Besuch des Knotenpunktes :
0 0
0
0
0
0
0
6
286 6 2 6 -6 82:;:;: 6 2 6 6 286 6 2:;:;: 6 2
Genauso kann es eingesehen werden, dass eine LIFO-Liste die0 Tiefsuche realisiert: Wenn die Suche einen Knotenpunkt durch die Kante 6 2 als erstes
besucht hat, werden danach nicht die zu , sondern zuerst die zu dem neu besuchten Knotenpunkt benachbarte Knotenpunkte besucht. Ebenso wird hier
ein Beispiel der Liste vor und nach dem Besuchen des Knotenpunktes zur Veranschaulichung gezeigt:
0
0
0
0
0
vor Besuch des Knotenpunktes : -6 2 6 6 286 6 2 6 -6 82:;:;: 6 2
nach Besuch des Knotenpunktes :
0 0 0
0
0
0
0
6 286
6 2:;:;: 6 286 6 2 6 -6 2 6 6 2:;:<: -6 2
6.3. Es ist trivial, dass alle drei Algorithmen ohne Markierung der besuchten
Knotenpunkte betrachtet identisch sind: sie implementieren eine linksrekursive
Tiefensuche. Die Unterbäume des binären Baumes sind nach dem folgenden Aufrufschema besucht:
traversiere(x)
{traversiere(x.links);
traversiere(x.rechts);
34
}
Der Tiefennummer eines Knotenpunktes wird beim Eintritt in den Unterbaum,
dessen Wurzel der Knotenpunkt ist, ausgeteilt – das ist identisch mit dem visit(x)
Befehl des Preorder-Verfahrens, der vor dem Besuch der Söhne aufgerufen wird.
Der Abschlussnummer für einen Knotenpunkt wird nach dem Besuch aller Söhne
des Knotenpunktes ausgegeben, was dieselbe Effekt hat, als wäre ein visit(x) Befehl nach traversiere(x.rechts) – genau wie bei der Postorder Traversierung. Damit
ist die Equivalenz der Algorithmen gezeigt.
6.4. Es wird ein konstruktiver Beweis angegeben. Seien die Knotenpunkte des zu
konstruierenden Graphen mit den Zahlen 6;:;:;: 6 nummeriert.5 Sei der Graph
vollständig und seien die Kanten wie folgt gerichtet: für 6
76;:;:;: 6 ? , falls
0 0
0 0
%2 und 76 2
%2 , also sind die Kanten von Knotenpunk, ist 6 2
ten mit kleineren Zahlen zu Knotenpunkten mit grösseren Zahlen gerichtet. ist
ein DAG, weil die Knotenpunkte in wachsender Reihenfolge der Nummerierung
eine gültige Stufenzerlegung angeben. Alle einfache Graphen mit weniger als Kanten können aus dem vollständigen Graphen mit dem Verlassen von Kanten
bekommen werden. Der so erhaltene Graph wird ebenfalls ein DAG sein, da aus
einem DAG Kanten entfernt, aber nicht dazugenommen worden sind.
6.5. Als erster Schritt werden leere Adjazenzlisten für jeden Punkt bis konstruiert. Es werden dann die Einträge der einzelnen Knotenpunkte in der originalen Adjazenzlisten sequentiell überprüft. Falls sich unter den Nachbarn des Knotenpunktes einen Eintrag befindet, wird einen Eintrag zu der Liste des
Knotenpunktes zugefügt. Da die Bearbeitung eines Eintrags
in konstant viele
Schritte möglich ist und es Knotenpunkte und
insgesamt
Nachbarn
in der Ad10
jazenzliste gibt, terminiert der Algorithmus in 2 Schritte. Da die Länge der
0
0
Ausgabe 1 2 ist, müssen jegliche Algorithmen eine Zeitschranke 2
haben, also ist der Algorithmus grössenordnungsmässig optimal.
6.6. Bemerkung: in der Aufgabe werden die Bezeichnungen der in der Vorlesung
behandelten Methode, beschrieben in [Vorlesungsskript] verwendet.
Sei angenommen, dass der Algorithmus die Komponenten in einer falschen Reihenfolge ausgibt. Ohne Beschränkung der Allgemeinheit wird es gesagt, dass die
falsche0 Reihenfolge aus der Richtigen mit dem Vertauschen der Komponente
2 zu bekommen ist. In diesem Fall gibt es eine Kante in , die
und
aus in läuft (siehe Abbildung 9/b). In dem Graphen läuft deswegen aus
der Komponente nach (siehe Abbildung 9/c). In diesem Fall aber wäre es bei
der zweiten Tiefensuche in möglich gewesen, die Komponente aus durch
35
a
e
b
c
e
Abbildung 9: die starken Komponenten von einem Graph, Aufgabe 6.6.
zu erreichen. Da in der Tiefensuche von zuerst die Komponente besucht
wurde, würden und eine starke Komponente bilden, was ein Widerspruch ist.
Es werden also die Komponenten in der richtigen Reihenfolge ausgegeben.
6.7. Zur Erinnerung: Jeder Baum wählt die minimale benachbarte Kante aus.
Am Anfang sind alle Punkte als einpünktige Bäume zu verstehen.
Die schon genommenen Kanten werden blau gefärbt. Sei der blauen Kanten.
der Graph
Konstruieren wir den Hilfsgraphen folgenderweise: Zu jeder Komponente (Baum)
von wird ein Punkt in aufgenommen. Die Kanten von sind die von den
Komponenten ausgewählten Kanten in .
Da der Algorithmus zu jeder Komponente von eine Kante gewählt hat, kann
es in keinen isolierten Punkt geben, also bestehen alle Komponenten von mindestens aus 2 Punkten. Jede Komponente in wird nun zu einem Punkt zusammengezogen, in werden die entsprechenden Komponenten zu eine Komponente verschmolzen.
Die Anzahl der Komponenten in wurde also mindestens halbiert in
höchstens 7 Iterationen haben wir den aufspannenden Baum gefunden, da es
dann nur eine Komponente in geben wird.
6.8. Es wird bewiesen, dass jeder maximale Fluss ein blockierender Fluss ist.
Gebe es in dem betrachteten Netzwerk einen Fluss , der maximal, aber nicht
blockierend ist. In diesem Fall gibt es einen Weg im Netzwerk, der kei0
0 0 ne gesättigte Kante enthält, also ) so, dass
29
2 2 . Dann
können aber die Flusswerte aller Kanten in und somit auch der Flusswert von
36
mit vergrössert werden. Das widerspricht der Maximalität von , also ist jeder
maximale Fluss auch ein blockierender Fluss.
Die Ungültigkeit der umgekehrten Richtung lässt sich durch einen Beispiel zeigen:
3(3)
s
3(3)
2(3)
t s
1(1)
2(3)
3(3)
0(1)
3(3)
3(3)
t
3(3)
Abbildung 10: ein blockierender Fluss und ein Fluss mit einem grösseren
Flusswert im selben Netzwerk
In Abbildung 10 ist ein blockierender Fluss mit dem Flusswert , und ein Fluss mit
dem Flusswert im selben Netzwerk dargestellt, also ist nicht jeder blockierender
Fluss ein maximaler Fluss.
6.9. Wir modifizieren den Algorithmus von Dijkstra folgenderweise: Sei 0
2 die Anzahl der bis jetzt gefundenen kürzesten Wege.
In jeder Iteration:
1. Wir wählen den Punkt aus den noch nicht fertigen Punkten aus, dessen Ab stand von den fertigen Punkten minimal ist: , ! )( minimal
2. Wir erweitern
die Menge der fertigen Punkte mit diesem Punkt:
5
$
?
3. Wir aktualisieren die -Werte aller noch nicht fertigen Punkte. Hier wird
einer der folgenden drei Fälle eintreten:
Entweder haben wir durch die Aufnahme von einen kürzeren Weg
gefunden, in diesem Fall wird der -Wert des Punktes mit dem von
überschrieben, da es nun genau
! ,( kürzeste Wege gibt, die alle
durch gehen.
Oder wir haben weitere gleich lange Wege gefunden (genau ! ,( Stück)
und der -Wert des Punktes muss mit dem von inkrementiert werden.
37
Der dritte Fall (nämlich dass wir einen längeren Weg gefunden haben)
ist uninteressant.
Formal ausgedrückt:
$
wenn ! ,( "! 6 ( wenn ! ,( "! 6 ( 4. Auch
! ( , dann ! (3$ ! ( , dann ! 3
( $
! ,(
! ( ! )(
muss (wie im Algorithmus von Dijkstra) aktualisiert werden.
Falls alle Punkte fertig sind, entsprechen die -Werte der Anzahl der kürzesten
10
2 wie beim Algorithmus von Dijkstra.
Wege. Der Zeitbedarf ist
6.10. Hier werden zwei Lösungen gegeben:
a) Die Methode PERT gibt einen kritischen Weg im Graphen an, was ein längster Weg ist.
b) Betrachte man eine topologische Ordnung 6 6#3:<:;: . (Es existiert eine
topologische Ordnung, denn der Graph ist ein DAG. Die topologische Ordnung
kann man schnell angeben.) Sei folgenderweise definiert:
5
0 0
2 %2
?)6
0
0
0
0
2 %2
,6 '286 %2 6
0 76 92 '6 0 286
die -Werte der alten Kanten bleiben unverändert.
Wir können annehmen, dass der Anfangspunkt des längsten Weges in ist.
Der längste Weg in ist zugleich der längste Weg in , falls man die Kante aus
0
weglässt. Bezeichne man die Länge des längsten Weges von nach mit 92 .
0
Sei ! ,( 76 %2 . Nun iteriere man folgenderweise:
0
0
0
92$ 23 6 92
0 und ! ,(3$ , falls die Kante 692 das Maximum geleistet hat. (Gibt es mehrere solche Kanten, wählt man eine beliebige aus.)
0
0
0
Für einen gegebenen Punkt sind die 2 -Werte für alle 692
%2 Kanten
wegen der topologischen Ordnung schon bekannt.
Am Ende ist der Endpunkt des längsten Weges der Punkt mit dem maximalen
0
endlichen 92 Wert.
Anhand des Arrays kann man den längsten Weg mit der gelernten Methode
rückwärts rekonstruieren. (Die Punkte in umgekehrter Reihenfolge: -6 ! ,( 6 ! ! ,( ( 6<:;:;:
bis erreicht wird.)
10
Dazu benötigt man insgesamt 2 Schritte.
38
6.11. Ein gieriger Algorithmus besitzt die gewünschten Eigenschaften. Die Methode wird in Pseudokode angegeben und ihre Korrektheit anschliessend mit vollständiger Induktion bewiesen.
//Initialisierung
choose vertex x with at least 1 neighbor;
classify(x, A);
classify(neighbor(x), B);
//Iteration
while exists unclassified vertex k
{
k_A = number of neighbors to A;
k_B = number of neighbors to B;
if (k_B >= k_A) classify(k, A) else classify(k, B);
}
Knotenpunkte des Graphen in zwei Punktenklassen
Induktionsschritt: seien und ,
6
schon so eingeordnet, dass mindestens die Hälfte der
Kanten des von
aufgespannten Teilgraphen zwischen und laufen. Sei
der nächste einzuordnende Knotenpunkt und habe er & Nachbarn aus und &
& (der andere Fall kann analog behandelt werden). In diesem
aus . Sei &
Fall wird von dem Algorithmus
in die Punktenklasse eingeordnet. Zwischen
5
? und
den Punktenklassen
laufen mindestens die Hälfte der Kanten des
5
?
von
aufgespannten Teilgraphen wegen Folgendem: Erstens, laut der
Induktionsannahme liefen zwischen und mindenstens die Hälfte der Kanten
des von
aufgespannten Teilgraphen. Zweitens, die Anzahl der Kanten zwischen den zwei Punktenklassen wurde mit & , die Anzahl der Kanten innerhalb
Punktenklasse wurde mit & vergrössert. Drittens, es gilt & & und viertens,
die Anzahl der Kanten innerhalb Punktenklasse wurde nicht vergrössert.
Es muss noch der Anfangsschritt angegeben werden. Sei einen Teilgraph mit zwei
Knotenpunkten und einer Kante betrachtet. Gehöre ein Knotenpunkt in Punkten
klasse , der andere in . Dieser Graph erfüllt die Induktionsbedingung.
Der Algorithmus macht Iterationen und in jeder muss er sämtliche Nachbarn des
10
einzuordnenden Knotenpunktes verarbeiten. Das ergibt eine Zeitschranke 2 , also arbeitet der Algorithmus in linearer Zeit.
6.12. Das Brett wird mit einem Graph repräsentiert, wobei jeder Knotenpunkt in
dem Graphen ein Feld des Bretts entspricht. Zwei Knotenpunkte sind benachbart
39
genau dann, wenn die entsprechenden Felder in dem Schachbrett mit einem Pferdesprung voneinander erreichbar sind.
0
-0
Da ein Pferd höchstens Felder schlagen kann, gilt es: %2%$
92 (siehe Abbildung 11). Auf dem Brett befinden sich & gegnerische Pferde. Alle Felder, auf denen ein Pferd steht oder auf die ein gegnerischer Pferd
schlagen kann, werden aus dem Graphen entfernt. Ob ein Feld entfernt werden
soll oder nicht, kann in konstant vielen Schritten getroffen werden, wenn der
-0
Graph mit einer Adjazenzliste gegeben ist. Wegen '2 müssen es höchstens
&% 7& Knotenpunkte aus dem Graphen entfernt werden, also ist diese Operation
10
82 Schritten zu ausführen. In dem übriggebliebenen Graphen ist mit einer
in
Traversiermethode aus der Position unseres Pferdes als Startpunkt die Menge der
erreichbaren Knotenpunkte zu bekommen. Da der Graph
höchstens Knoten10
2 Schritte. Somit hat
punkte und Kanten hat, braucht die Traversierung
10
der Algorithmus Zeitschranke 2 .
Abbildung 11: mögliche Schritte aus einem Feld, Aufgabe 6.12.
6.13. Zuerst ermittle man mit dem Algoritmus von Floyd die Abstände zwischen
10 allen Punktpaaren. Das benötigt
2 Schritte. Mit dem Algorithmus bekommt
man eine Matrix . In allen Spalten von wird nach dem maximalen Wert gesucht
0
(d.h. für 92 ). Hier wird -mal das Maximum von Elementen gesucht, was in
0
0
0
2 Zeit möglich ist. Am Ende bestimme man 92 ; das ist in
32
0
Zeit möglich. Die Punkte mit den kleinsten 92 Wert sind die Zentren von .
6.14. Wir konstruieren einen aufspannenden Baum von (z.B. mit BFS oder
0
DFS) in
2 Schritten.5 Die Blätter des Baumes sind sicherlich keine Artikulationspunkte, denn ? wird von dem Rest des aufspannenden Baumes
zusammengehalten.
1. Die Adjazenzmatrix von ist:
40
f
3
b
1
6
5
1
d
1
4
2
1
a
3
6
e
2
c
6.15.
Abbildung 12: Der Graph zur Aufgabe 6.15.
(Vergleiche mit Abbildung 12)
Die Menge
und die
5
5 ?
5 6 ;?
5 6 46
5 6 46
5 6 46
6 46
-Werte nach jeder Iteration:
A !
?
?
?
6 6 6
!
! A!
! !
?
(
6
6 6
(
(
(
(
(
2. Die gefragte Kanten dürfen
in keinem
minimalen
Weg enthalten
0 0
0
0
0 0
sein. Diese Kanten sind: 46 2 , A6 2 , 6 2 , 6 2 , 6 2 , -6 2 .
6.16. Sei folgenderweise definiert. Seien die Punkte von die 4 lange Teilzeichenketten. So bekommt man Punkte, da es genau soviele Teilzeichenketten
gibt. (Zwei Teilzeichenketten können einander überlappen.)
41
Eine Kante wird zwischen zwei Knotenpunkten gezogen, falls die Punkte die
Grenzen eines gültigen Blocks bilden. Die Kante soll vorwärts gerichtet sein,
das heisst der Leserichtung der Bitfolge entsprechen. (Siehe Abbildung 13.) Der
0
Graph kann in 2 Schritten aufgebaut werden.
??XY
XY??
Abbildung 13: Gültiger Block und dazugehörige Kante zur Aufgabe 6.16.
ist ein DAG, und zwar schon topologisch geordnet. Eine gute Zerteilung der
Bitfolge auf gültige Blöcke ist äquivalent mit einem Weg in von dem ersten bis
zu dem letzten Punkt.
Hier muss man also einen Weg vom ersten zum letzten Punkt finden, das geht in
0 2 Zeit.
6.17.
6.18.
7
Die Sprache NP
7.1. Es wird ein Algorithmus angegeben, der die Methode als Subroutine benutzt. Zuerst wird mit
ermittelt, ob der Graph mit Farben färbbar ist. Falls
nicht, terminiert der Algorithmus. Sonst wird ein beliebig gefärbter Klikk mit drei
aufgenommen und der folgende Schritt auf sämtliche
Punkten als Hilfsgraph
Punkte durchgeführt:
Zwei Punkte von werden mit dem gerade bearbeiteten Punkt zusammengebunden und er bekommt die Farbe des dritten Punktes. Da mit drei Farben färbbar
ist, sind die zwei Punkte im , mit denen nach dem Einziehen der neuen Kanten
der Graph mit drei Farben färbbar bleibt, in höchstens drei Versuche zu finden.
Nachdem alle Punkte bearbeitet wurden, wird der resultierende Graph immer noch
mit drei Farben färbbar, und für jedes Punkt in wird eine Farbe festgelegt sein.
Das ergibt eine korrekte Färbung.
42
7.2. Ein möglicher Hinweis ist der Wert von . Mit diesem kann es in Polynomzeit beantwortet werden, ob die Eingabe in der Sprache ist. Es ist noch zu
beweisen, dass die Länge von nicht ”zu gross” sein kann. Sei eine Lösung,
0 dann gilt : ::, 2 . ist durch teilbar, denn
6;:;:;: 6;:;:;: . Davon folgt
, also dass die Länge des Hin
weises kleiner als die von der Eingabe ist. Somit gilt:
.
7.3. Gesucht ist ein Algorithmus, der nicht mehr als ( ist eine positive Konstante) Speicherzellen benutzt.
0
Seien die zwei Punktenklassen und und sei %
. Sei 2 . Eine Paarung wird ein-eindeutig mit einer Permutation von Zahlen beschrieben, nämlich mit den Endpunkten der Kanten in einer der Punktenklassen.
Um zu entscheiden, ob genau & Paarungen hat, ist ein denkbarer Verfahren,
alle mögliche Paarungen zu kontrollieren. Bis zu verschiedene Paarungen sind
möglich, aber für das Kontrollieren einer Paarung muss gleichzeitig nur die der
Paarung entsprechende Permutation in dem Speicher gehalten werden. Da die Be ,
schreibung einer Permutation Speicherzellen benötigt, ist die Sprache in +
generiert werden
falls die nacheinanderkommenden Permutationen in können. Hier wird ein Verfahren in Pseudokode angegeben, die die Permutationen
von Elementen generiert:
perm(1, ... n)
{1, perm(2,
2, perm(1,
...
i, perm(1,
...
n, perm(1,
}
... n);
3, ... n);
... i-1, i+1, ... n);
... n-1);
perm(i)
{i;}
+
Es ist einfach zu sehen, dass eine , die diesen Algorithmus realisiert, in arbeitet, also ist die Sprache in .
0
%2 7.4. Die Sprache ist in
: ein Hinweis sei einen Weg, der aus
Kanten besteht. Dieser erfüllt die zwei Forderungen für Hinweise bei Sprachen in
trivialerweise. Im Folgenden wird eine Karp-Reduktion auf das HamiltonWeg-Problem gezeigt.
43
Sei einen Graphen gegeben; die Aufgabe ist es, einen Hamiltonischen Weg
in zu finden. Es wird ein isolierter
Knotenpunkt zu dazugenommen und
5
der resultierender Graph bezeichnet. Im wird ein Weg der
? als 0 0
Länge
2 2 mit dem Algorithmus gesucht. Einen Weg der
0 Länge
entspricht einem Hamilton-Weg in . Das Dazunehmen
2 > in eines Knotenpunktes ist in Polynomzeit durchführbar, also ist die Transformation
eine Karp-Reduktion auf den Hamilton-Weg-Problem, der
-vollständig ist.
Die Sprache ist also
-vollständig.
7.5. Die Anzahl aller möglichen Teilmengen ist bekanntlich
. Aus
Symmetriegründen ist die Anzahl der möglichen 6
Paare # . Die generate
and-test-Methode ist also keineswegs polynomial.
Stattdessen können wir gezielt diejenige Aufteilungen der Punkte suchen, die solche Punktmengen erzeugen, die höchstens durch zwei Kanten verbunden sind.
Das heisst, durch das Entfernen von maximal zwei Kanten soll der Graph in zwei
Komponenten zerfallen. Der Algorithmus geht wie folgt:
Ist der Graph nicht zusammenhängend (dieses kann man in Polynomzeit
entscheiden), kann er in zwei Komponenten zerlegt werden, so dass zwi
.
schen die Komponenten keine Kante führt. Falls der Graph zusammenhängend ist, aber durch das Entfernen einer Kante in zwei Komponenten zerfällt, hat man zwei Komponenten gefunden, die
genau eine Kante verbindet, also ist der Graph
.
Existiert keine solche Kante, soll man wie folgt vorgehen: Falls durch das
Entfernen zweier Kanten nicht mehr zusammenhängend bleibt, haben wir
zwei Komponenten gefunden zwischen denen genau zwei Kanten führen,
also ist .
War keiner der drei Schritte erfolgsreich, existiert keine solche Aufteilung
der Punkte, die die obige Bedingungen erfüllt, also ist .
10 2 -mal testen, ob ein
Insgesamt müssen wir also höchstens Graph mit Punkten zusammenhängend ist. Das heißt, es ist in Polynomzeit ent
scheidbar, ob ein Graph
ist.
7.6.
. Nach der Stirling-Formel ist
0
7 7 7
28:
Da die Länge des Outputs eine exponentielle Funktion der Länge des Inputs
ist, gehört nicht zu .
1. Die Länge des Outputs ist 7
44
2. Die Primfaktorzerlegung lässt sich auf dieses Problem zurückführen. Nach
dem heutigen Stand der Wissenschaft bleibt diese Frage offen.
3. Wir haben als Input die binäre Darstellung von . Sei die Position des von
& . Da )
links (allgemein:
von der MSB-Richtung) ersten true-Bits
0
, ist 3
2 & . Das Output zu generieren dauert
lang, also
ist
.
7.7.
1. & -FARBE
Eine Färbung mit & Farben ist ein guter Zeuge. Ob das wirklich eine richtige
Färbung ist oder nicht, kann man in Polynomzeit überprüfen. Es ist genug zu
kontrollieren, ob alle Punkte mit genau einer der & Farben gefärbt wurden,
und die benachbarte Knotenpunkte verschiedene Farben bekommen haben.
0
Das geht in 2 Schritten.
2. Es ist bekannt, dass 3-FARBE
-vollständig ist.
& ) ist.
3. Nun wird gezeigt, dass 3-FARBE & -FARBE, wobei *
Sei der Graph, über dem es zu entscheiden ist, ob er mit Farben färbbar
ist. Konstruiere man folgenderweise:
0
0
2 $
0
%2
0
2 $
82
0
5 0
2
6
'2
0
286
0
%2 6 0
28?
(Das heisst, nehmen wir einen vollständigen Graphen mit &+ Punkten zu
, und verbinden wir alle Punkte von mit allen Punkten von
).
Falls mit & Farben färbbar ist, wird höchstens mit Farben gefärbt,
sind mit allen anderen Knotenpunkten von denn die Punkte von
in nicht vorverbunden, und so können die Farben der Punkte von
kommen. Umgekehrt gilt es auch: kann mit höchstens 3 Farben gefärbt
werden, ist ohne weiteres & -färbbar, nämlich sollen die Punkte von
die andere &. Farben haben.
Das heisst: ist genau dann mit 3 Farben färbbar, falls mit & Farben
färbbar ist.
7.8. In eine Kiste können höchstens 2 Gegenstände gepackt werden.
1. Die Gegenstände, deren Gewicht grösser oder gleich ist, kommen allein
in die Kisten.
45
2. Die gebliebenen Gegenstände, deren Gewicht zwischen und ist, können
im besten Fall gepaart werden. Definiere man einen bipartiten Graphen folgenderweise: die Punkte beider Punktklassen sind zu den Gegenständen
zugeordnet. Die Punkte sind verbunden, falls die Gegenstände und
in einer Kiste gepackt werden können. In diesem Graphen soll man eine
maximale Paarung suchen. Die Endpunkte der Kanten der Paarung sind die
Gegenstände, die gepaart in die Kisten kommen, die nicht bedeckten Punkte
kommen allein in die Kisten. Eine maximale Paarung ist äquivalent damit,
dass möglichst viele Gegenstände gepaart in die Kisten kommen. Das ist –
zusammen mit der gegebenen Bedingung – mit der minimalen Anzahl von
Kisten äquivalent.
7.9.
7.10.
7.11.
2.
1.
Die Teilmenge selbst ist ein guter Hinweis, der in Polynomzeit kontrolliert
werden kann.
MAX - UNABHÄNGIG
Sei der Input von dem MAX - UNABHÄNGIG Problem der Graph , und die
Zahl . (Es ist zu entscheiden, ob der Graph eine unabhängige
Punktmenge mit mindenstens Knotenpunkten hat). Bestehe aus den
Punkten von und von weiteren Knotenpunkten, die mit allen
Punkten von verbunden werden, aber unter einander sind sie disjunkt.
Sei & . Falls es in mindestens unabhängige Punkte gibt,
bilden diese Punkte mit den neuen Punkten einen bipartiten Graphen mit
& Punkten. Die andere Richtung lautet folgenderweise: falls es in einen
bipartiten Teilgraphen mit Punkte gibt, soll mindestens einer der
sein, und mindestens aus
Punkte – sei es mit bezeichnet – aus . Falls es eine Kante unter den Punkten von gebe, würde es mit ein Dreieck bilden, aber ein Graph, der mit 2 Farben färbbar ist, kann keine
Dreiecke beinhalten.
7.12.
1. PARTITION TMSP
Mit der folgenden Parameterwahl sind die zwei Probleme äquivalent:
46
:
2.
TMSP
RSP
Man wähle die Werte & und $ . Der
mit diesen Parametern eine Lösung, wofür gilt:
und
RSP
Algorithmus sucht
4:
So wird RSP äquivalent mit TMSP.
7.13.
2.
1. MAXKREIS
Ein guter Hinweis ist der Kreis von Länge & selbst, was in Polynomzeit
kontrolliert werden kann.
HAMILTON - KREIS
MAXKREIS
beantwortet die Frage,
ob es in einem Graphen einen Kreis
0
2 ist diese Frage mit dem HAMILTON der Länge & gibt. Mit & KREIS Problem äquivalent, d. h. HAMILTON - KREIS MAXKREIS.
MAXKREIS
7.14.
2.
1. HAMILTON - WEG
Ein guter Hinweis ist der Hamiltonsche Weg selbst, was schnell (in Polynomzeit) kontrolliert werden kann.
HAMILTON - KREIS
HAMILTON - WEG
Hier soll man entscheiden, ob der Graph einen Hamiltonschen Kreis beinhaltet, wobei man das HAMILTON - WEG Problem als eine Subroutine benutzen kann.
0
6 %2 $
Hamiltonscher Kreis in Hamiltonscher Weg
0 0
6 und
6 '2
2
0 0
2 kontrollieren, ob ein
Das heisst, man soll für alle Kanten 6 '2
Hamiltonscher Weg
in existiert.
Man muss noch irgendwie garantieren, dass die Subroutine die Existenz
eines Hamiltonschen Weges zwischen und im Graphen entscheidet.
Dazu modifiziere man den Graphen folgenderweise:
Sei :
0
0
2 $
0
2 $
0
%2
%2
5
6 )
? 6
5 0
0
6 286 -6 928?):
47
Es existiert ein Hamiltonscher Weg in zwischen
wenn es in einen (beliebigen) Hamiltonschen Weg
0 0
lich bei 6 2 anfängt, und mit -6 92 endet.
7.15.
und genau dann,
gibt, da
sicher-
a)
Eine notwendige Bedingung für die Existenz eines Spannbaumes
von ist, dass zusammenhängend ist.
Indirekt: Bezeichene man 2 Kom
mit und .
ponenten von muss von auch erreichen,
was nur durch möglich ist, aber
die Punkte von haben Grad 1 in
, Widerspruch.
In kann ein spannender Baum mit einer beliebigen Methode
(BFS, DFS, usw.) gesucht werden. Falls es von einem Knotenpunkt keine Kante nach führt, dann gibt es keinen solchen
Baum, da nur Nachbarn aus haben kann, aber in einem Baum kön
nen zwei Punkte mit Grad 1 nicht benachbart sein. Falls einen
Nachbar in hat, soll man sie mit einer Kante mit einem von ihren
Nachbarn verbinden, damit man am Ende einen guten aufspannenden
Baum bekommt.
b)
ist
-vollständig
Der spannende Baum ist ein guter Zeuge. Es kann in Polynomzeit
überprüft werden, ob der spannende Baum richtig ist.
HAMILTON - WEG
Es ist zu entscheiden, ob es in einem gegebenen Graphen ein Ha
0
miltonscher Weg existiert. Man
2
5 soll für alle Punktpaare 6
laufen lassen, mit 6 -? . Der spannende Baum, in dem die
Punkte von genau die Punkte mit Grad 1 sind, ist ein Hamiltonscher
Weg.
7.16.
1.
Die abdeckende Punktmenge überprüft werden kann.
ist ein guter Hinweis, da sie in Polynomzeit
48
2.
MAX - UNABHÄNGIG
Die Existenz einer abdeckenden Punktmenge mit höchstens & Punkten
ist äquivalent damit, dass es eine unabhängige Punktmenge mit mindenstens
0
ist abdeckend
%2 A& Punkte gibt, da ist unabhängig.
7.17.
7.18.
7.19.
Literatur
[Vorlesungsskript] A. Orban und Z. Mann: Vorlesung über Algorithmentheorie
BME SZIT 2001.
49
Herunterladen