Upload
others
View
34
Download
0
Embed Size (px)
Citation preview
Modul: Programmierung B-PRG Grundlagen der Programmierung 1 – Teil 2
Softwaretechnik
Prof. Dr. O. DrobnikProfessur Architektur und Betrieb verteilter SystemeInstitut für InformatikFachbereich Informatik und Mathematik
Softwaretechnik
Kapitel 2 – Entwurf von Algorithmen
Grundlagen der Programmierung 1
2.1 Greedy-Methode2.2 Divide and Conquer – Methode2.3 Backtracking-Methode2.4 Graphbasierte Algorithmen
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 3
Übersicht - 2. Entwurf und Implementierung
2.1 Greedy-Methode2.1.1 Methode2.1.2 Sortieren2.1.3 Konvexe Hülle
2.2 Divide and Conquer – Methode2.2.1 Methode2.2.2 Mergesort2.2.3 Maximum-Contiguous-Subvector Problem2.2.4 Naiver Ansatz2.2.5 Divide and Conquer Ansatz für MCS-Problem2.2.6 Scanning-Algorithmus2.2.7 Türme von Hanoi
2.3 Backtracking-Methode2.3.1 Methode2.3.2 Konvexe Hülle: Graham Scan
2.4 Graph-basierte Algorithmen
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 4
2.1 Greedy-Methode
2.1.1 MethodeStufenweises VorgehenSukzessives Betrachten der EingabewerteAuswahlfunktion: Reihenfolge für die Betrachtung der EingabewerteEntscheidung: gehört Eingabewert zur Lösung oder nichtEinfache Entwurfsmethode, auf vielfältige Problemstellungen anwendbar
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 5
2.1.2 Sortieren
Spezifikation des SortierproblemsGegeben: Liste mit und Elementen
aus NatGesucht: Anordnung der Elemente von , so dass
Beispiel:
v[0] ≤ v[1] ≤ . . . ≤ v[len(v)− 1]
v len(v) = N
v
v = [1, 87, 65, 78, 39, 114, 90, 66]
sort(v)−−−−→ v = [1, 39, 65, 66, 78, 87, 90, 114]
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 6
Sortieren – Anwendung
Sortieren ist ein klassisches Problem der InformatikDatenbanken jeglicher Ausführung erfordern häufig den Einsatz effizienter SortieralgorithmenAus diesem Grund wird jeder vorgestellte Sortieralgorithmus bezüglich seines Berechnungsaufwandes (Laufzeit) abgeschätzt. In der Praxis gibt es viele Punkte, die für die Wahl des optimalen Sortieralgorithmus wichtig sind:
Welche Daten sollen sortiert werden (Integer, Strings, …) ?Wie groß ist der Datensatz?Nach welcher Vergleichsfunktion soll sortiert werden?Wie weit sind die Daten vorsortiert?Wie viel Speicher steht zur Verfügung?Sind doppelte Einträge vorhanden?
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 7
Selection Sort
Einer der einfachsten Sortier-Algorithmen arbeitet wie folgt:
Finde zuerst das kleinste Element in der Folge und vertausche es mit dem Element in der ersten Position.Finde das zweit-kleinste Element, und vertausche es mit dem Element in der zweiten PositionFahre in dieser Weise fort, bis die gesamte Folge sortiert ist.
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 8
Programm: selection_sort
def selection_sort(v):for p in range(len(v)-1):# v ist sortiert im Bereich [0,…,p-1]
vmin = p# vmin ist der Index des aktuell alsminimal betrachteten Wertes
for q in range(p, len(v)):if v[q] < v[vmin]:
vmin = qtemp = v[vmin] # Austauschv[vmin] = v[p] # von v[vmin]v[p] = temp # und v[p]
return v
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 9
Berechnungsaufwand Selection Sort
Um das kleinste Element zu finden, müssen maximal Elemente betrachtet werden.Für das zweite maximal , für das dritte Insgesamt werden maximal
Elemente betrachtet.Für große ist der dominierende Term, wir sagen:„Die Laufzeit ist in der Größenordnung von “
PNi=1 i =
(N+1)N2 = N2+N
2
N
N−1 N−2, . . .
N N2
N2
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 10
2.1.3 Konvexe Hülle
Gegeben ist eine Punktmenge von N Punkten in der Ebene. Gesucht sei die konvexe Hülle der Punktemenge, d. h. das kleinste konvexe Polygon, das alle Punkte der Menge enthält.Konvexe Hülle: Jede Strecke, die zwei Punkte innerhalb des Polygons verbindet, muss vollständig innerhalb des Polygons liegen.
Konvex nicht konvex
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 11
Konvexe Hülle – Anwendung
Bei der heute immer wichtiger werdenden 3D-Programmierung sind effiziente Algorithmen zur Berechnung der komplexen Hülle sehr wichtigWill man berechnen, ob sich zwei Körper berühren, (collision detection) testet man zuerst, ob sich deren konvexe Hüllen berühren.Nur wenn sich die konvexe Hüllen berühren, startet die Berechnung mit den Körpern.Dies bedeutet in den meisten Fällen einen erheblich geringeren Berechnungsaufwand.
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 12
Package Wrapping (Paket einhüllen)
Package Wrapping ist der “natürlichste” Algorithmus: er ähnelt der Vorgehensweise des Menschen, eine konvexe Hülle zu zeichnen:
Man wähle einen geeigneten Startpunkt, der garantiert auf der Hülle liegt,nehme einen horizontalen Strahl und bewege ihn solange im Gegenuhrzeigersinn, bis ein weiterer Punkt getroffen wird; dieser Punkt muss auf der Hülle sein;wiederhole die Prozedur von diesem neuen Punkt aus usw. bis letztlich der Startpunkt wieder erreicht wird, d. h. die Punktemenge vollständig “eingehüllt”ist.
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 13
Das Modul random in Python
random.random(): Gibt eine zufällige Fließkommazahl aus dem Bereich [0.0, 1.0) zurück.
uniform(a,b): Gibt eine zufällige Fließkommazahl aus dem Bereich [a, b] zurück.
randint(a,b): Gibt eine zufällige ganze Zahl N (Integer) zurück mit a ≤ N ≤ b.
seed([x]): Initialisiert den Zufallszahlengenerator mit dem gegebenen seed x. Wird kein seedangegeben, benutzt random die Systemzeit als seed.
Beispiel:
>>> import random>>> random.random()0.88588698998139825>>> random.randint(0,9)9>>> random.randint(0,9)1>>> random.randint(0,9)0>>> random.randint(0,9)2>>> random.uniform(100,101)100.44436367099409
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 14
Erzeugen der Punktemenge: Liste p
class Point:def __init__(self, x, y):
self.x = xself.y = y
def test(n):import randomp = []for i in range(n):
p.append(Point(random.randint(0,100), random.randint(0,100)))
h = convex_hull(p) # Aufruf des Hauptprog.print h
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 15
Programm convex_hull
Startpunkt: Punkt mit der kleinsten y-Koordinate: pmin
Zwischenergebnis: hull = [pmin]
def convex_hull(pset):# Punkt mit kleinster y-Koordinate suchen,# dieser liegt in jedem Fall auf der# Hülle.pmin = pset[0]for p in pset:
if p.y < pmin.y:pmin = p
hull = [pmin]# danach folgt Hauptteil
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 16
Programm convex_hull
Bestimme den nächsten Punkt: hull = [pmin, p]
Θ
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 17
Programm convex_hull
Seien -Punkte bis einschließlich in “hull”Suche den nächsten Punkt für die Hülle: 1
Es gilt für :
(Drehung im Gegenuhrzeigersinn)
ist minimalunter allen (Hüllenforderung)
Θi+1Θi+1 ≥ Θi
Θi+1Θ ≥ Θi
Pii
Pi+1
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 18
Berechnung des Winkels
Vorbetrachtung
wird nur zum Sortieren benötigt.Es genügt daher eine leicht zu berechnende Funktion, deren Anordnungseigenschaft der einer Winkelfunktion äquivalent ist.
..
Θ
dy
dx
Pi+1
ΘPi
tanΘ = dydx ⇒ Θ = tan−1 dydx
t = dydx+dy
Θ
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 19
Berechnung des Winkels
def theta(p1, p2):dx = float(p2.x - p1.x)dy = float(p2.y - p1.y)ax = abs(dx)ay = abs(dy)if dx == 0 and dy == 0:
t = 0else:
t = dy/(ax + ay)if dx < 0:
t = 2.0 - telif dy < 0:
t = 4.0 + treturn t * 90.0
Θ
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 20
Hauptteil von convex_hull
def convex_hull(pset):thetaold = 0while True:
thetamin = 360.0p1 = hull[-1]for p2 in pset:
if not p2 == p1:thetanew = theta(p1, p2)if thetanew >= thetaold:
if thetanew < thetamin:thetamin = thetanewpnext = p2
thetaold = thetaminif pnext == hull[0]:
breakhull.append(pnext)
return hull
…
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 21
Demonstration
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 22
2.2 Divide and Conquer – Methode
2.2.1 MethodeTeile (Divide)
Teile das Problem der Größe N in (wenigstens) zwei annähernd gleichgroße Teilprobleme, wenn N > 1 ist.Ist ein Teilproblem hinreichend klein (z.B. N = 1), so löse es direkt und breche so die Rekursion im Lösungsschema ab.
Herrsche (Conquer)Löse die Teilprobleme auf dieselbe Art.
Vereinige (Merge)Füge die Lösungen für die Teilprobleme zur Gesamtlösung zusammen.
N>1N
N=1
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 23
2.2.2 Sortieren mit Divide & Conquer
MergesortDivide:Teile die zu sortierende Liste in zwei gleichgroße Teillisten,
Conquer:sortiere beide Teillisten rekursiv,
Merge:vereinige die beiden sortierten Teillisten zu einer sortierten Gesamtliste.
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 24
Algorithmus merge_sort
Da eine Liste der Länge 1 immer sortiert ist, genügt es die Gesamtliste in solch kleinen Listen zu teilen und diese zu vereinigen (merge).
def merge_sort(list):if len(list) <= 1: # Rekursionsverankerung
return listelse:
length = len(list)# Liste in zwei Teillisten teilen (divide)list1 = list[:length/2]list2 = list[length/2:]# Rekursiver Funktionsaufruf (conquer) auf die # Teillisten und Rückgaben vereinigen (merge) return merge(merge_sort(list1),merge_sort(list2))
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 25
Merge
Funktionsweise von Merge:Gehe durch beide sortierte Teillisten und verschiebeimmer das kleinste Element aus beiden Teillisten in die Gesamtliste.
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 26
Funktion mergedef merge(list1, list2):
merged_list = [] #initialisiere leere Gesamtlistewhile len(list1) != 0 and len(list2) != 0:
# Solange beide Listen noch Elemente besitzen, wird das # kleinste Element aus den Teillisten entfernt und in# die Gesamtliste eingefügtif list1[0] > list2[0]:
merged_list.append(list2.pop(0))else:
merged_list.append(list1.pop(0))if len(list1) != 0:
merged_list.extend(list1)if len(list2) != 0:
merged_list.extend(list2)return merged_list
# Falls eine der Teillisten noch Elemente enthält, werden die an die Gesamtliste gehängt.
# Liste.pop(0) gibt des erste Element der Liste zurück und löscht dieses aus der Liste.
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 27
Aufwandsabschätzung
Für eine Liste der Länge haben nach maximal
Divide-Ebenenalle Teillisten die Länge .Nach genau so vielen Merge-Ebenen entsteht die sortierte Gesamtliste.In jeder Ebene werden höchstens Elemente bewegt.Die Laufzeit ist also in einer Größenordnung von
und ist somit schneller als Selection Sort
N
N
1
¡N2¢
log2(N) + 1
N log2(N)
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 28
2.2.3 Maximum-Contiguous-SubvectorProblem
Gegeben:Folge v von N ganzen Zahlen in einer Liste;die Folge muss mindestens ein Element enthalten.
Gesucht:die maximale Teilsumme, d.h. die maximale Summe aller Elemente in einer zusammenhängenden Teilfolge. (maximale Teilfolge)Sind alle Elemente negativ, so sei die maximale Teilfolge die leere Folge, deren Summe gleich 0 ist.
v N
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 29
Maximum-Contiguous-Subvector Problem
Maximale Teilsumme:
v[0] = 31v[0] + v[1] = −10 < 0 −→ 0v[0] + v[1] + v[2] = 49 < v[2] = 59
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 30
Formalisierung des Problems
Anwendung: Betrachtet man die täglichenKursschwankungen einer Aktie, so ist die maximaleTeilsumme der maximale Gewinn.
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 31
2.2.4 Naiver Ansatz
Ansatz: Betrachte für jeden Index der Folge die von diesem ausgehenden Teilfolgen
MaxSoFar: bisher gefundene maximale Teilsumme
def mcsv_simple(v):MaxSoFar = 0for i in range(len(v)):
sum = 0for s in v[i:]:
sum = sum + sMaxSoFar = max(MaxSoFar, sum)
return MaxSoFar
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 32
Naiver Ansatz
Die Anweisungen innerhalb der äußeren Schleife werdenN-mal durchlaufen,die Anweisungen innerhalb der zweiten Schleife werdenjeweils höchstens N-mal bei jeder Ausführung deräußeren Schleife durchlaufen, dh. die Laufzeit ist in der Größenordnung von N 2
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 33
2.2.5 Divide and Conquer Ansatz für MCS-Problem
Teilt man eine gegebene Folge in der Mitte, so liegt die maximale Teilfolge
entweder ganz in einem der beiden Teilstücke
oder sie umfasst die Trennstelle, liegt also teils im linken undteils im rechten Teil.
Für das in einem Teil liegende Stück der maximalen Teilfolge, die die Trennstelle umfasst, gilt: Die Summe der Elemente ist maximal unter allen zusammenhängenden Teilfolgen in diesem Teil, die das Randelement an der Trennstelle enthalten.
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 34
Divide and Conquer Ansatz für MCS-Problem
def mcsv_dv(v):if len(v) == 1:
return max(0, v[0])left = v[:len(v)/2]right = v[len(v)/2:]MaxInLeft = mcsv_dv(left)MaxInRight = mcsv_dv(right)sum = 0MaxCrossing = 0left.reverse()for s in left:
sum = sum + sMaxCrossing = max(MaxCrossing, sum)
sum = MaxCrossingfor s in right:
sum = sum + sMaxCrossing = max(MaxCrossing, sum)
return max(MaxInRight, MaxInLeft, MaxCrossing)
Div.
Conq.
Merge
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 35
Beispiel
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 36
Beispiel
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 37
Aufwandsabschätzung (grobe Betrachtung)
Anzahl der Schritte (mit der Annahmed.h. ):
Teilung in jeder Teilung maximal weitere Schritte
wird mal durchlaufen ( : max. Schritte)
ungefähr Schritte nötig
ist besser als
N = 2k − 1k = log2(N + 1)
≈ log2NN
N
C
C Clog2N
N · log2NN2
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 38
2.2.6 Scanning-Algorithmus
Scanning-PrinzipProbleme auf Folgen können oft dadurch gelöst werden, daß man – ausgehend von einer Lösung für
– untersucht, wie man diese für erweitern kann.
AnsatzSpeicherung des bereits gefundenen Ergebnisses Hinzunahme von Hilfsdaten zur Berechnung des neuen Resultats
Aufwand
v[0, . . . , i− 1]v[0, . . . , i]
≈ N
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 39
Bezug zum MCS-Problem
Wir durchlaufen sequentiell die Positionen von v in der Ordnung der Positionen, d. h. MaxSoFar: bereits gefundene maximale TeilsummeWir führen eine neue Variable ein (“Hilfsdaten”): MaxEndingHere
0, 1, · · · , len(v) − 1.
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 40
Formalisierung von MaxEndingHere
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 41
Algorithmus
def mcsv_lin(v):MaxSoFar = 0MaxEndingHere = 0for s in v:
MaxEndingHere = max(MaxEndingHere + s, 0)MaxSoFar = max(MaxSoFar, MaxEndingHere)
return MaxSoFar
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 42
2.2.7 Türme von Hanoi
n Steine unterschiedlichen Durchmessers sollen von einem Stapel auf einen anderen gebracht werden, wobei ein Hilfsstapel benutztwerden darf (Problem der Größe n). Dabei sind folgende Bedingungen einzuhalten:
es darf stets nur ein Stein, und zwar der oberste eines Stapels,bewegt werden,zu keiner Zeit darf ein Stein auf einem kleineren liegen.
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 43
Lösungsansatz
Vorbedingung: alle Steine mit Nummer auf Stapel i.
Nachbedingung: alle Steine mit Nummer auf Stapel j.
Umsetzen eines Steines von Stapel i auf j:Auf Stapel i und j dürfen sich nur größere Steine als der zu bewegende Stein befinden.Alle kleineren Steine müssen deshalb zu diesem Zeitpunkt auf dem dritten Stapel k liegen.
Formal:Wenn für Stein x von Stapel i auf Stapel j gebracht wird, müssen alle kleineren Steine auf dem Stapel mit der Nummer
liegen.
x, x+ 1, . . . , n
x, x+ 1, . . . , n
i, j ∈ {1, 2, 3}
k = 6− (i+ j)
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 44
Rekursion
Aufspaltung des Gesamtproblems:alle Steine von Stapel i auf Stapel
Stein x von i auf j
alle Steine von auf Stapel j
Aufspaltung führt zur Rekursion: die zu lösenden Teilprobleme sind identisch mit der ursprünglichen Aufgabe, werden aber für eine kleinere Eingabe gelöst.
Das Türme-von-Hanoi Problem demonstriert die Eleganz und Kürze rekursiver Lösungsansätze.
k = 6− (i+ j)
k = 6− (i+ j)
x+ 1, . . . , n
x+ 1, . . . , n
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 45
Python Programm
# n Anzahl Steine# slice Stein mit Nummer slice# help Hilfsstapel# source Ausgangsstapel# dest Zielstapeldef hanoi(n, slice, source, dest):
print "hanoi(%s,%s,%s,%s)" % (n, slice, source, dest)help = 6 - source - destif slice < n:
hanoi(n, slice + 1, source, help)print "Scheibe %s von %s auf %s" % (slice, source,dest)if slice < n:
hanoi(n, slice + 1, help, dest)© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 46
hanoi(3,1,1,2)#Ausgabe:# hanoi(3,1,1,2)# hanoi(3,2,1,3)# hanoi(3,3,1,2)# Scheibe 3 von 1 auf 2# Scheibe 2 von 1 auf 3# hanoi(3,3,2,3)# Scheibe 3 von 2 auf 3# Scheibe 1 von 1 auf 2# hanoi(3,2,3,2)# hanoi(3,3,3,1)# Scheibe 3 von 3 auf 1# Scheibe 2 von 3 auf 2# hanoi(3,3,1,2)# Scheibe 3 von 1 auf 2
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 47
Aufwandsabschätzung
Anzahl Schritte:Größenordnung: (exponentielle Laufzeit)Welche Auswirkungen hat eine exponentielle Laufzeit?
Angenommen wir können 1.000.000 Berechnungen pro Sekunde durchführen.
4 ·1016 y0.01s0.00066sN = 100
12d0.0016s0.00021sN = 40
3 ·10288 y 1s0.01sN = 1000
17m0.0009s0.00014sN = 30
1s0.0004s0.000086sN = 20
0.001s0.0001s0.000033sN = 10
2NN2N log2(N)
2N − 1
Anzahl Atome im Universum ist ca. 1078
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 48
2.3 Backtracking-Methode
2.3.1 MethodeVersuch-und-Irrtum-Prinzip (trial and error):
Auswahl eines möglichen LösungswegsVerfolgen dieses Lösungswegs soweit wie möglichFalls Lösungsweg nicht fortgesetzt werden kann, ersetzen der letzten Entscheidung durch eine AlternativeGgf. iteriertes Rücksetzen der Entscheidungen
Unterschied zu Greedy:Greedy: exhaustives Verfahren – untersucht alle LösungswegeBacktracking: versucht, offensichtlich falsche Lösungswege frühzeitig zu vermeiden (nicht weiter zu verfolgen)
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 49
2.3.2 Konvexe Hülle: Graham Scan
Sortiere Punkte so, dass die Hüllenpunkte in derReihenfolge vorliegen, die man beim Durchlaufen derkonvexen Hülle im Gegenuhrzeigersinn erhält.
Ankerpunkt: kleinste y-Koordinate, größte x-KoordinateSortierung: theta-Funktion (siehe 2.1.2)Man erhält durch die Sortierung der Punkte einenPolygonzug, der alle Punkte umfasst und sich selbstnicht schneidet
Die ersten beiden Punkte liegen auf der Hülle. Sukzessive Hinzufügen aller Punkte:Bei jedem Punkt prüfen, ob seine Vorgänger tatsächlich auf der konvexen Hülle liegen.
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 50
ccw-Funktion
Dann gelten folgendeGeradensteigungen:
Es sei:
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 51
ccw-Funktion
Reise von zu zu :
Drehung im Gegenuhrzeigersinn
Drehung im UhrzeigersinnProblem: oder daher ProduktbildungProblem: Kollinearität der Punkte, d.h. Steigungen sind gleich.Lösung: Funktion ccw wird dreiwertig definiert. Sind kollinear, dann:
ccw = -1: P0 ist zwischen P2und P1
ccw = 0 : P2 ist zwischen P0und P1
ccw = 1 : P1 ist zwischen P0und P2
dx1 dx2 = 0
P0, P1, P2
P0 P1 P2
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 52
Python-Programm
def ccw(p0, p1, p2):dx1 = p1.x - p0.xdy1 = p1.y - p0.ydx2 = p2.x - p0.xdy2 = p2.y - p0.yif (dx1*dy2 > dy1*dx2):
return +1if (dx1*dy2 < dy1*dx2):
return -1if ((dx1*dx2 < 0) or (dy1*dy2 < 0)):
return -1if ((dx1*dx1 + dy1*dy1) < (dx2*dx2 + dy2*dy2)):
return +1return 0
Die Punkte sind kollinear.Es werden drei kollineareFälle unterschieden:1) p0 zwischen p1 und p2: ccw = -12) p1 zwischen p0 und p2: ccw = +13) p2 zwischen p0 und p1: ccw = 0
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 53
Graham Scan
def grahamscan(p):lowest = Nonefor q in p:
if lowest == None or q.y < lowest.y:lowest = q
for q in p:if q.y == lowest.y and q.x > lowest.x:
lowest = qp.sort(lambda p1, p2: cmp(theta(lowest, p1),
theta(lowest, p2)))hull = p[0:3]for trypos in range(3, len(p)):
while ccw(hull[-2],hull[-1],p[trypos]) < 0:del hull[-1]
hull.append(p[trypos])return hull
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 54
Beispiel
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 55
Aufwandsabschätzung
Eingabe: N Punkte
Finden des Minimums (kleinstes y, dann größtes x),
jeder Punkt wird einmal betrachtet: N
Punkte nach Winkeln sortieren (z.B. mit Mergesort):
Für jeden Punkt testen ob dieser auf der Hülle liegt:ccw führt eine begrenzte Anzahl an Befehlen aus und hängt nicht von N ab.ccw wird fast N mal aufgerufen.
Insgesamt dominiert das Sortieren der Punkte die Laufzeit.grahamscan hat eine Laufzeit in der Größenordnung von
N log2N
N log2N© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 56
2.4 Graph-basierte Algorithmen
Ein Graph wird mit dargestellt.V (vertices) ist die endliche Menge der Knoten.E (edges) ist die endliche Menge der Kanten.
Beispiel:
G = (V,E)
V = {v0, v1, v2}E = {(v0, v1), (v1, v2)}
G = (V,E)
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 57
Minimaler Spannbaum (MST)
Spezifikation des Problems:Gegeben ist ein ungerichteter zusammenhängender Graph mit einer Kostenfunktion Gesucht ist ein aufspannender Baum minimaler Größe(MST = Minimum Spanning Tree)
Ein Spannbaum ist ein Teilgraph eines ungerichteten Graphen, der ein Baum ist und alle Knoten des Graphen enthält. (Spannbäume existieren nur in zusammenhängenden Graphen.)Ein Spannbaum heißt minimal, wenn in demselben Graphen kein anderer Spannbaum mit geringeren Kosten existiert.
G = (V,E) GE : E → Nat0
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 58
Beispiel MST
G
MST(G)
MSTG
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 59
Minimaler Spannbaum – Anwendung
Minimale Spannbäume werden dort berechnet, wo man kostengünstige zusammenhängende Netzwerke (z.B. Telefonnetzwerke, elektrische Netze u. a.) herstellen will.Bei Computernetzwerken mit redundanten Pfaden werden Spannbäume zur Vermeidung von Paketverdopplung genutzt.Mit Hilfe von Spannbäumen können auch Labyrinthe erzeugt werden. Auf Grund der Zyklenfreiheit besitzen solche Labyrinthe stets nur einen Lösungsweg.
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 60
Kruskal-Algotrithmus
Idee: Wähle fortgesetzt die kürzeste (billigste) Kante aus G, die zu keinem Zyklus im MST führt.Algorithmus:
Betrachte die Kanten eines Graphen in aufsteigender Reihenfolge (nach Kosten sortiert)Füge die Kante und die Knoten zum MST hinzu, falls dadurch kein Zyklus erzeugt wird.Um die Zyklenbildung zu vermeiden, werden die Mengen der verbundenen Knoten betrachtet. Für gilt: Es gibt einen Weg zwischen und .Eine Kante wird nur dann zum MST hinzugefügt, wenn und gilt. In diesem Fall wird auch ein erzeugt, das und ersetzt.
e = (v1, v2) v1, v2
C1, . . . , CN
v1, v2 ∈ Ci v1 v2e = (v1, v2)
v1 ∈ Ci, v2 ∈ Cj Ci 6= CjCk = Ci ∪ Cj Ci
Cj
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 61
Beispiel
{A,B},{C},{D},{E},{F}
( A, B )
{A},{B},{C},{D},{E},{F}
MSTKante Ci
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 62
Beispiel (2)
{A, B}, {C, D, F}, {E}
( D, F )
{A, B}, {C, F}, {D},{E}
( C, F )MSTKante Ci
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 63
Beispiel (3)
{A, B, C, D, F}, {E}( B, F )
{A, B, C, D, E, F}( C, E )
Nicht erlaubt, da A und D Elemente der Menge {A, B, C, D, F} sind.
( A, D )
MSTKante Ci
Fertig!
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 64
Repräsentation von Graphen
Wir betrachten ungerichtete Graphen:
__init__: Erzeugt einen Graphen→ Graph
addvertex: Hinzufügen eines KnotensGraph x Vertex → Graph
addedge: Hinzufügen einer markierten KanteGraph x Vertex x Vertex x Nat → Graph
getvertices: Liefert die Menge der KnotenGraph → Pot (Graph)
getedges: Liefert sortierte Folge von Kanten aufsteigend nach Kosten sortiert
Graph → Pot ( Vertex → Vertex → Nat )
cost: Liefert Kosten zu einer Kante des Graphen sofern Kante existiert, sonst None
Graph x Vertex x Vertex → Nat ∪{None}
e = ((v1, v2) , c)
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 65
Das Modul copy
Das Modul bietet generische Kopier-Operationenimport copy # Laden des Moduls
Oberflächliche Kopie (shallow copy):y = copy.copy(x)
Ein Objekt y wird als Kopie von x erzeugt. Referenzen aus x werden übernommen. Ausführliche Kopie (deep copy):y = copy.deepcopy(x)
Ein Objekt y wird als Kopie von x erzeugt. Es werden rekursiv Kopien aller Objekte aus Referenzen aus x erzeugt.
Vom Benutzer definierte Klassen können die Kopier-Methoden überschreiben (__copy__(), __deepcopy__())
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 66
itemgetter, map, sorted
itemgetter(i): liefert eine Funktion zurück, die ihrerseits das i-te Element einer Sequenz zurückgibt. itemgetter(i)ist teil des Moduls operator.
map(func, list): führt die Funktion func auf jedem Element der Liste list aus.
sorted(list[, key [, reverse]]): gibt eine neue sortierte Liste zurück mit den Elementen aus list.key: eine Funktion mit einem Argument, die auf jedes Element
der Liste angewandt wird, um die Schlüssel für die Sortierung zu erhalten.
reverse: eine boolesche Variable, die die Reihenfolge der Sortierung angibt. (Bei True wird die Reihenfolge umgedreht.)
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 67
Beispiel
>>> from operator import itemgetter>>> inventar = [('Birne', 3),('Apfel', 4),('Orange',2)]>>> map(itemgetter(0),inventar)['Birne', 'Apfel', 'Orange']>>> map(itemgetter(1),inventar)[3, 4, 2]>>> sorted(inventar, key=itemgetter(0))[('Apfel', 4), ('Birne', 3), ('Orange', 2)]>>> sorted(inventar, key=itemgetter(1))[('Orange', 2), ('Birne', 3), ('Apfel', 4)]
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 68
Die Graph-Klasse
import copyfrom operator import itemgetterclass Graph:
def __init__(self):self.knotenListe = []self.kantenListe = []
def addvertex(self, v1):if v1 not in self.knotenListe:self.knotenListe.append(v1)
def addedge(self, v1, v2, c):if not v1 == v2:
self.addvertex(v1)self.addvertex(v2)for i in self.kantenListe:
a1 = i[0][0]a2 = i[0][1]if a1 == v1 and a2 == v2:
self.kantenListe.remove(i)self.kantenListe.append(((v1,v2),c))
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 69
Die Graph-Klasse (2)
def getvertices(self):return copy.copy(self.knotenListe)
def getedges(self):kanten = copy.copy(self.kantenListe)return sorted(kanten, key=itemgetter(1))
def cost(self, v1, v2):ret = Nonefor i in self.kantenListe:
a1 = i[0][0]a2 = i[0][1]if a1 == v1 and a2 == v2:
ret = i[1]return ret
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 70
Beispiel-Graphg = Graph()g.addvertex('A')g.addvertex('B')g.addvertex('C')g.addvertex('D')g.addvertex('E')g.addvertex('F')g.addedge('A','B',10)g.addedge('A','D',30)g.addedge('A','E',70)g.addedge('B','C',50)g.addedge('B','E',60)g.addedge('B','F',25)g.addedge('C','E',35)g.addedge('C','F',15)g.addedge('D','F',20)g.addedge('E','F',55)
print "Kruskal:", kruskal(g).getedges()Kruskal: [(('A', 'B'), 10), (('C', 'F'), 15), (('D', 'F'), 20),
(('B', 'F'), 25), (('C', 'E'), 35)]
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 71
Beispiel
Graph.getedges liefert Kantenliste in folgender Form:
Ist dann ist
[((v0, v1), c01) , ((v1, v2), c12)]
e[0] = (v0, v1)
e = ((v0, v1), c01)
e[0][0] = v0
e[0][1] = v1
e[1] = c01
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 72
Algorithmus kruskaldef kruskal(g): # Eingabe: g Objekt der Klasse Graphsets = [] # Menge der Cifor v in g.getvertices(): # Einfügen von allen v‘s
sets.append([v]) # in verschiedene Ci‘smst = Graph() # Erzeuge leeren MSTfor e in g.getedges(): # Durchlaufen der Kanten nach ihren Kosten sortiert
v1 = e[0][0] # Erster Knoten der Kantev2 = e[0][1] # Zweiter Knoten der Kantes1 = findset(sets, v1) # Ci des ersten Knotens2 = findset(sets, v2) # Cj des zweiten Knotenif s1 != s2: # Wenn Ci ungleich Cj:
mst.addedge(v1,v2,e[1])# Kante (+Kosten) hinzufügenjoinset(sets,s1,s2) # Ci und Cj vereinigen
if len(mst.getvertices()) == len(g.getvertices()):break # Wenn mst alle Knoten aus g enthält: Ende
return mst
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 73
Hilfsfunktionen
# Eingabe: Menge der C‘s und Knoten vdef findset(sets, v):
for s in sets:if v in s:
return s# Ausgabe: Das Ci, das v enthält
# Eingabe: Menge der C‘s, s1=Ci und s2=Cjdef joinsets(sets, s1, s2): # die Vereinigung von s1 und s2 wird an Stelle von s1 abgespeichert.
sets[sets.index(s1)] = s1 + s2sets.remove(s2)
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 74
Aufwandsabschätzung
Sortieren der Kanten (z.B. mit Merge-Sort) Es wird höchstens jede Kante einmal betrachtet Findset braucht in unserem Beispiel maximal Zugriffe.Sowohl das Sortieren als auch kruskal selbst haben eine Laufzeit in der Größenordnung von
Mit besseren Datenstrukturen kann die Größenordnung auf begrenzt werden.
(|E|)|E|
|E| log2(|E|)
|E| log2(|E|) + |E|2
|E| log2(|E|)