modul: programmierung b-prg softwaretechnik grundlagen der
TRANSCRIPT
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 Schrittweise Verfeinerung
© 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 Konvexe Hülle
2.2 Divide and Conquer – Methode2.2.1 Methode2.2.2 Maximum-Contiguous-Subvector Problem2.2.3 Naiver Ansatz2.2.4 Divide and Conquer Ansatz für MCS-Problem2.2.5 Scanning-Algorithmus2.2.6 Türme von Hanoi
2.3 Backtracking-Methode2.3.1 Methode2.3.2 Konvexe Hülle: Graham Scan
2.4 Schrittweise Verfeinerung© 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
Basisalgorithmus (Greedy)
def Greedy(input):result = []while len(input) != 0:
s = selectfrominput() # Auswahlif solution(s):
result.append(s)input.remove(s)
return result
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 6
2.1.2 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 7
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 8
Erzeugen der Punktemenge: Liste p
class Point:def __init__(self, x, y):
self.x = xself.y = y
def test(n):from rand import randp = []for i in range(n):
p.append(Point(rand() % 1000, rand() % 1000))
h = convex_hull(p) # Aufruf des Hauptalg.print h
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 9
Algorithmus 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]
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 10
Algorithmus convex_hull
Bestimme den nächsten Punkt: hull = [pmin, p]
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 11
Algorithmus convex_hull
Seien i-Punkte bis einschließlich Pi in “hull”Suche den nächsten Punkt für die Hülle: Pi+1
Es gilt für Өi+1:Өi+1 ≥ Өi(Drehung im Gegenuhrzeigersinn)Өi+1 ist minimalunter allen Ө ≥ Өi(Hüllenforderung)
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 12
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.
dxdyΘtan =
dydxdyt+
=
dxdytanΘ 1−=
dy
dxӨ
⇒
Pi
Pi+1
..
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 13
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 14
Convex_hull: Hauptteil
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 15
Demonstration
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 16
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.
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 17
2.2.2 Maximum-Contiguous-SubvectorProblem
Gegeben:Folge v von N ganzen Zahlen in einer Liste;die Folge muss mindestens ein Element enthalten.
Gesucht:maximale Summe aller Elemente in einer zusammenhängenden Teilfolge, maximaler Teilsumme: maximale Teilfolge.
Sind alle Elemente negativ, so sei die maximale Teilfolge die leere Folge, deren Summe gleich 0 ist.
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 18
Maximum-Contiguous-Subvector Problem
Maximale Teilsumme:
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 19
Formalisierung des Problems
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 20
2.2.3 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 21
Naiver Ansatz
Die Anweisungen innerhalb der äußeren Schleifewerden N-mal, die innerhalb der zweiten Schleife jeweilshöchstens N-mal bei jeder Ausführung der äußerenSchleife durchlaufen, dh. die Laufzeit ist in derGrößenordnung von N2.
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 22
2.2.4 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 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 23
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 24
Beispiel
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 25
Beispiel
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 26
Aufwandsabschätzung (grobe Betrachtung)
Anzahl der Schritte (mit der Annahme N = 2k − 1d. h. k = log2(N + 1)):
Teilung ≈ log2 Nin jeder Teilung maximal N weitere Schritte C
C wird log2 N mal durchlaufen (C : max. N Schritte)
ungefähr N · log2 N Schritte nötig
ist besser als N2
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 27
2.2.5 Scanning-Algorithmus
Scanning-PrinzipProbleme auf Folgen (arrays) können oft dadurch gelöst werden, daß man – ausgehend von einer Lösung für v[0 · · · i − 1] – untersucht, wie man diese für v[0 · · · i] erweitern kann.
AnsatzSpeicherung des bereits gefundenen Ergebnisses Hinzunahme von Hilfsdaten zur Berechnung des neuen Resultats
Aufwand ≈ N
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 28
Bezug zum MCS-Problem
Wir durchlaufen sequentiell die Positionen von v in der Ordnung der Positionen, d. h. 0, 1, · · · , len(v) − 1 MaxSoFar: bereits gefundene maximale TeilsummeWir führen eine neue Variable ein (“Hilfsdaten”): MaxEndingHere
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 29
Formalisierung von MaxEndingHere
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 30
Algorithmus
def mcsv_lin(v):MaxSoFar = 0MaxEndingHere = 0# {0 ≤ MaxEndingHere ≤ MaxSoFar}for s in v:
# {0 ≤ MaxEndingHere ≤ MaxSoFar}# Vorbedingung:# {Pindex(s−1) = MaxSoFar = # MaxSoFar[0 · · · index(s) − 1] ^ # MaxEndingHere = MaxEndingHereindex(s)−1}MaxEndingHere = max(MaxEndingHere + s, 0)MaxSoFar = max(MaxSoFar, MaxEndingHere)# Nachbedingung:# {MaxSoFar = MaxSoFar[0 · · · index(s)] ^# MaxEndingHere = MaxEndingHereindex(s)}
return MaxSoFar
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 31
2.2.6 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 32
Lösungsansatz
Vorbedingung: alle Steine mit Nummer x, x + 1, · · · , n auf Stapel i.Nachbedingung: alle Steine mit Nummer x, x + 1, · · · , n 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 i, j {1, 2, 3} Stein x von Stapel i auf Stapel j gebracht wird, müssen alle kleineren Steine auf dem Stapel mit der Nummer k = 6 − (i + j) liegen.
∈
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 33
Divide and Conquer
Aufspaltung des Gesamtproblems:alle Steine x + 1, · · · , n auf Stapel k = 6 − (i + j)Stein x von i auf jalle Steine x + 1, · · · , n von k = 6 − (i + j) 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.
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 34
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 35
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 36
Aufwandsabschätzung
Anzahl Schritte:Größenordnug: 2n - 1
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 37
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 38
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 39
ccw-Funktion
Dann gelten folgendeGeradensteigungen:
Es sei:
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 40
ccw-Funktion
Reise von P0 zu P1 zu P2:
Drehung im Gegenuhrzeigersinn
Drehung im UhrzeigersinnProblem: dx1 oder dx2 = 0daher ProduktbildungProblem: Kollinearität der Punkte, d.h. Steigungen sind gleich.Lösung: Funktion ccw wird dreiwertig definiert. Sind P0, P1, P2 kollinear, dann:
ccw = -1 : P0 ist zwischen P2 und P1
ccw = 0 : P2 ist zwischen P0 und P1
ccw = 1 : P1 ist zwischen P0 und P2
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 41
Graham Scan
def grahamscan(p):global lowestlowest = 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 42
Graham Scan
def grahamscan(p):global lowestlowest = 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
Punkte mit kleinster y-Koordinate und unter diesen den mit maximaler x-Koordinate suchen
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 43
Graham Scan
def grahamscan(p):global lowestlowest = 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
Die restlichen Punkte nach dem Winkel zwischen der Horizontalen und Geraden, die sie mit ‘lowest’ verbindet sortieren.
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 44
Graham Scan
def grahamscan(p):global lowestlowest = 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
Die ersten beiden Punkte liegen in jedem Fall auf der konvexen Hülle, der dritte Punkt wird zunächst hinzugenommen.
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 45
Graham Scan
def grahamscan(p):global lowestlowest = 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
Die Variable ‘trypos’ enthält den Index des Punktes in ‘p’, den wir der Hülle hinzufügen.
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 46
Beispiel
© J.W.G-Universität Frankfurt a.M.Praktikum Grundlagen der Programmierung Folie 47
2.4 Schrittweise Verfeinerung
Problem (maschinell lösbar)Analyse, Abstraktion, Spezifizieren
Spezifikation (Eingabe, Ausgabe)
Zerlegung in Unterprobleme- Identifizieren von Unterproblemen- Analysieren, Spezifizieren von
Unterproblemen (Eingabe/Ausgabe)
Zusammensetzung der Gesamtlösungaus den Lösungen der Unterprobleme- Algorithmus, der Unteralgorithmen "aufruft"
- Sichere KorrektheitSchätze Aufwand
ggf. weitere Zerlegungevtl. Neuentwurf
Für nichtelementare Unter-algorithmen: Entwurf durchweitere ZerlegungKorrektheit, Aufwand
Maschine, die Elementaralgorithmenausführen kann