Modul: Programmierung B-PRG Softwaretechnik Grundlagen der ... · Modul: Programmierung B-PRG...

19
Modul: Programmierung B-PRG Grundlagen der Programmierung 1 – Teil 2 Softwaretechnik Prof. Dr. O. Drobnik Professur Architektur und Betrieb verteilter Systeme Institut für Informatik Fachbereich Informatik und Mathematik Softwaretechnik Kapitel 2 – Entwurf von Algorithmen Grundlagen der Programmierung 1 2.1 Greedy-Methode 2.2 Divide and Conquer – Methode 2.3 Backtracking-Methode 2.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-Methode 2.1.1 Methode 2.1.2 Sortieren 2.1.3 Konvexe Hülle 2.2 Divide and Conquer – Methode 2.2.1 Methode 2.2.2 Mergesort 2.2.3 Maximum-Contiguous-Subvector Problem 2.2.4 Naiver Ansatz 2.2.5 Divide and Conquer Ansatz für MCS-Problem 2.2.6 Scanning-Algorithmus 2.2.7 Türme von Hanoi 2.3 Backtracking-Methode 2.3.1 Methode 2.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 Methode Stufenweises Vorgehen Sukzessives Betrachten der Eingabewerte Auswahlfunktion: Reihenfolge für die Betrachtung der Eingabewerte Entscheidung: gehört Eingabewert zur Lösung oder nicht Einfache Entwurfsmethode, auf vielfältige Problemstellungen anwendbar

Transcript of Modul: Programmierung B-PRG Softwaretechnik Grundlagen der ... · Modul: Programmierung B-PRG...

Page 1: Modul: Programmierung B-PRG Softwaretechnik Grundlagen der ... · Modul: Programmierung B-PRG Grundlagen der Programmierung 1 – Teil 2 Softwaretechnik Prof. Dr. O. Drobnik Professur

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

Page 2: Modul: Programmierung B-PRG Softwaretechnik Grundlagen der ... · Modul: Programmierung B-PRG Grundlagen der Programmierung 1 – Teil 2 Softwaretechnik Prof. Dr. O. Drobnik Professur

© 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

Page 3: Modul: Programmierung B-PRG Softwaretechnik Grundlagen der ... · Modul: Programmierung B-PRG Grundlagen der Programmierung 1 – Teil 2 Softwaretechnik Prof. Dr. O. Drobnik Professur

© 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.

Page 4: Modul: Programmierung B-PRG Softwaretechnik Grundlagen der ... · Modul: Programmierung B-PRG Grundlagen der Programmierung 1 – Teil 2 Softwaretechnik Prof. Dr. O. Drobnik Professur

© 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]

Θ

Page 5: Modul: Programmierung B-PRG Softwaretechnik Grundlagen der ... · Modul: Programmierung B-PRG Grundlagen der Programmierung 1 – Teil 2 Softwaretechnik Prof. Dr. O. Drobnik Professur

© 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

Page 6: Modul: Programmierung B-PRG Softwaretechnik Grundlagen der ... · Modul: Programmierung B-PRG Grundlagen der Programmierung 1 – Teil 2 Softwaretechnik Prof. Dr. O. Drobnik Professur

© 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))

Page 7: Modul: Programmierung B-PRG Softwaretechnik Grundlagen der ... · Modul: Programmierung B-PRG Grundlagen der Programmierung 1 – Teil 2 Softwaretechnik Prof. Dr. O. Drobnik Professur

© 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

Page 8: Modul: Programmierung B-PRG Softwaretechnik Grundlagen der ... · Modul: Programmierung B-PRG Grundlagen der Programmierung 1 – Teil 2 Softwaretechnik Prof. Dr. O. Drobnik Professur

© 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

Page 9: Modul: Programmierung B-PRG Softwaretechnik Grundlagen der ... · Modul: Programmierung B-PRG Grundlagen der Programmierung 1 – Teil 2 Softwaretechnik Prof. Dr. O. Drobnik Professur

© 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

Page 10: Modul: Programmierung B-PRG Softwaretechnik Grundlagen der ... · Modul: Programmierung B-PRG Grundlagen der Programmierung 1 – Teil 2 Softwaretechnik Prof. Dr. O. Drobnik Professur

© 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

Page 11: Modul: Programmierung B-PRG Softwaretechnik Grundlagen der ... · Modul: Programmierung B-PRG Grundlagen der Programmierung 1 – Teil 2 Softwaretechnik Prof. Dr. O. Drobnik Professur

© 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

Page 12: Modul: Programmierung B-PRG Softwaretechnik Grundlagen der ... · Modul: Programmierung B-PRG Grundlagen der Programmierung 1 – Teil 2 Softwaretechnik Prof. Dr. O. Drobnik Professur

© 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)

Page 13: Modul: Programmierung B-PRG Softwaretechnik Grundlagen der ... · Modul: Programmierung B-PRG Grundlagen der Programmierung 1 – Teil 2 Softwaretechnik Prof. Dr. O. Drobnik Professur

© 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

Page 14: Modul: Programmierung B-PRG Softwaretechnik Grundlagen der ... · Modul: Programmierung B-PRG Grundlagen der Programmierung 1 – Teil 2 Softwaretechnik Prof. Dr. O. Drobnik Professur

© 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)

Page 15: Modul: Programmierung B-PRG Softwaretechnik Grundlagen der ... · Modul: Programmierung B-PRG Grundlagen der Programmierung 1 – Teil 2 Softwaretechnik Prof. Dr. O. Drobnik Professur

© 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

Page 16: Modul: Programmierung B-PRG Softwaretechnik Grundlagen der ... · Modul: Programmierung B-PRG Grundlagen der Programmierung 1 – Teil 2 Softwaretechnik Prof. Dr. O. Drobnik Professur

© 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)

Page 17: Modul: Programmierung B-PRG Softwaretechnik Grundlagen der ... · Modul: Programmierung B-PRG Grundlagen der Programmierung 1 – Teil 2 Softwaretechnik Prof. Dr. O. Drobnik Professur

© 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))

Page 18: Modul: Programmierung B-PRG Softwaretechnik Grundlagen der ... · Modul: Programmierung B-PRG Grundlagen der Programmierung 1 – Teil 2 Softwaretechnik Prof. Dr. O. Drobnik Professur

© 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

Page 19: Modul: Programmierung B-PRG Softwaretechnik Grundlagen der ... · Modul: Programmierung B-PRG Grundlagen der Programmierung 1 – Teil 2 Softwaretechnik Prof. Dr. O. Drobnik Professur

© 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|)