Prof. Dr. Tobias H aberlein · Algorithmik mit Python Prof. Dr. Tobias H aberlein Hochschule...
Transcript of Prof. Dr. Tobias H aberlein · Algorithmik mit Python Prof. Dr. Tobias H aberlein Hochschule...
Algorithmik mit Python
Prof. Dr. Tobias Haberlein
Hochschule Albstadt-SigmaringenStudiengang
”Kommunikations- und Softwaretechnik“
Leipzig, 04.04.2011
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 1 / 57
Uberblick1 Implementierung von Algorithmen
2 SortierenInsertion-SortQuicksort
3 SuchenHeapsSkip-ListenBloomfilterSuchmaschinen
4 GraphenGrundlagenKurzeste WegeMinimaler Spannbaum
5 Schwere ProblemeLosung des Traveling Salesman ProblemsGreedy-Heuristiken zur Losung des TSP
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 2 / 57
Implementierung von Algorithmen
Rekursion
Eine Funktion heißt rekursiv,wenn Sie sich selbst ein odermehrmals aufruft.
Pro: Oft einfacher zuimplementieren, als iterativeAnsatze.
Con: I. A. mehrSpeicherverbrauch
1 def facIter(n):
2 erg = 1
3 for i in range(1,n+1)
4 erg = erg*i
5 return erg
1 def facRec(n):
2 if n==0:
3 return 1
4 else:
5 return n*fac(n-1)
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 3 / 57
Implementierung von Algorithmen
Rekursive vs. Iterativ?
”Kochrezept“
1 Rekursionsabbruch:Was ist der
”einfache“ Fach
(Große n = 0 oder n = 1).2 Rekursionsschritt:
I Gedankentrick: Angenommen,Aufgabe fur alle
”kleineren“
Probleme gelost . . .I . . . wie kann man dann aus den
Losungen der kleineren Aufgaben,die Losung der Gesamtaufgabekonstruieren.
1 def rekAlg(x):
2 if len(x) is kleingenug:
3 return loesung(x)
4 else:
5 ...
6 y1 = rekAlg(x1)
7 y2 = rekAlg(x2)
8 ...
9 loesung = kombiniere(y1,y2,...)
10 return loesung
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 4 / 57
Implementierung von Algorithmen
Aufgaben: Rekursion (1)
Aufgabe 1
1 Definieren Sie die Funktion sum(n), die die Summe der Zahlen von 1
bis n berechnen soll, rekursiv.
2 Definieren Sie die Funktin len(lst), die die Lange der Liste lst
berechnen soll, rekursiv.
Aufgabe 2
Implementieren Sie die Funktion ins(x,lst), die die Liste aller moglichenEinfugungen des Elements x in die Liste lst zuruckliefert.Beispielanwendung:
>>> ins(1,[2,3,4,5])
>>> [[1,2,3,4,5], [2,1,3,4,5], [2,3,1,4,5], [2,3,4,1,5], [2,3,4,5,1]]
Tipp: Das geht uber eine rekursive Implementierung. Es empfiehlt sichauch die Verwendung einer Listenkomprehension.
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 5 / 57
Implementierung von Algorithmen
Aufgaben: Rekursion (2)... und noch etwas schwieriger:
Aufgabe 3
Implementieren sie eine rekursive Funktion perms(lst), die die Liste allerPermutationen der als Argument ubergebenen Liste lst zuruckliefert.Tipp: Verwenden Sie die eben definierte Funktion ins. Beispielanwendung:
>>> perms([1,2,3])
>>> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
Aufgabe 4
Implementierung Sie die rekursive Funktion choice(lst,k), die eine Listealler k-elementigen Teil
”mengen“ der Elemente aus lst zuruckliefert.
Beispielanwendung:
>>> choice([1,2,3],2)
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 6 / 57
Implementierung von Algorithmen
Rekursiv gehts einfacherDie rekursive Implementierung vieler Probleme ist viel einfacher!Beispiel: Zeichnen der Striche auf einem Lineal
Rekursive Implementierung:
1 from graphics import *
2 linealCanv = GraphWin("Ein Lineal",1000,50)
3
4 def strich(x,h):
5 '''Zeichne Strich an Position x mit Laenge h'''6 l = Line(Point(x,0),Point(x,h))
7 l.draw(linealCanv)
8
9 def lineal(l,r,h):
10 ''' Zeichne Lineal zwischen Pos l und r
11 laengster Strich (in der Mitte) hat Hoehe h'''12 ...
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 7 / 57
Implementierung von Algorithmen
Aufgabe 5
Zeichnen Sie durch einerekursiv definiertePython-Funktion und unterVerwendung dergraphics-Bibliothekfolgenden Stern:
Aufgabe 6
Schreiben Sie eine rekursive Prozedurbaum(x,y,b,h) zum Zeichnen eines(binaren) Baumes derart, dass die Wurzelsich bei (x,y) befindet, der Baum b breitund h hoch ist. Definieren Sie hierzu einePython-Prozedur line(x1,y2,x2,y2), dieeine Linie (x1,y2) zu (x2,y2) zeichnet.Beispiel fur die Ausgabe vonbaum(0,0,16,4).
1
2
1
3
4
16
(0,0)
16
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 8 / 57
Implementierung von Algorithmen
Destruktiv vs. Nicht-Destruktivlist.sort() ist destruktiv:
>>> l = list('hallo')>>>
l.sort() # l wird veraendert
>>> l
['a', 'h', 'l', 'l', 'o']
sorted(list) istnicht-destruktiv:
>>> l = list('hallo')>>>
sorted(l) # l unveraendert
['a', 'h', 'l', 'l', 'o']
Vor-/Nachteile
Pro Nicht-Destruktiv:
Jeder destruktive Update verandert internen Zustand des Programms.
Viele Zustande ⇒ viele Abfragen ⇒ viele mogliche Fehler
Wenige Zustande ⇒ besserer Uberblick ⇒ weniger mogliche Fehler
Con Nicht-Destruktiv:
... ? ...
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 9 / 57
Sortieren Insertion-Sort
Insertion-Sort – Funktionsweise
So sortiert der Kartenspieler:
Sukzessive werden Karten vom Stapel in die schon sortierten Kartenauf der Hand eingefugt.
[6,53,63,94,56,8,72,44,70]
[6,53,63,94,56,8,72,44,70]
[6,53,63,94,56,8,72,44,70]
[53,6,63,94,56,8,72,44,70]1.
3.
4.
2. [6,8,53,56,63,94,72,44,70]
[6,53,56,63,94,8,72,44,70]
8.
7.
6.
5.
[6,8,53,56,63,72,94,44,70]
[6,8,44,53,56,63,72,94,70]
[6,8,44,53,56,63,70,72,94]Ergebnis:
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 10 / 57
Sortieren Insertion-Sort
Insertion-Sort – Implementierung
Wir teilen auf ins das Einfugen:
1 def insAtRightPos(alst, key):
2 return [x for x in alst if x <=key] +[key] +
3 [x for x in alst if x>key]
und das eigentliche Sortieren – rekursiv implementiert.
1 def insertionSort(alst):
2 if len(alst)<=1: return alst
3 else: return ...
Aufgabe 7
Ersetzen sie die”...“-Stelle in obigem Listing durch den notwendigen
rekursiven Aufruf.
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 11 / 57
Sortieren Insertion-Sort
Insertion-Sort – Implementierung in-place
1 def insertionSort(lst):
2 for j in range(1,len(lst)):
3 key = lst[j]
4 i = j-1
5 while i >= 0 and lst[i] > key:
6 lst[i+1] = lst[i]
7 i = i -1
8 lst[i+1] = key
Zwar schneller, aber . . .
. . . schwieriger zu implementieren!
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 12 / 57
Sortieren Quicksort
Quicksort – Funktionsweise + Implementierung
Wahle beliebiges Element lstj mit 0 ≤ j ≤ n − 1 aus (Pivot-Element).
Zerteile lst in lstl (alle Elemente < lstj) und lstr (alle Elemente ≥ lstj)
lstl und lstr werden rekursiv sortiert.
Die rekursiv sortierten Teillisten werden einfach zusammengehangt.
1 def quicksort(lst):
2 if len(lst)<=1: return lst # Rekursionsabbruch
3 pivot = lst[0]
4 lst_l = [a for a in lst[1:] if a <= pivot]
5 lst_r = [a for a in lst[1:] if a > pivot]
6 return ...
Aufgabe 8
Vervollstandigen Sie die Implementierung von Quicksort an der
”...“-Stelle.
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 13 / 57
Sortieren Quicksort
Quicksort – Implementierung in-placeSchneller, aber schwieriger zu implementieren!
Die in-place-Partitionierung
1 def partitionIP(lst,l,r):
2 pivot=lst[l]
3 i=l-1
4 j=r+1
5 while True:
6 while True:
7 j=j-1
8 if lst[j]<=pivot: break
9 while True:
10 i=i+1
11 if lst[i]>=pivot: break
12 if i<j:
13 lst[i],lst[j]=lst[j],lst[i]
14 else:
15 return j
Das eigentlichein-place-Sortieren.
1 def quicksortIP(lst,l,r):
2 if r>l:
3 i= partitionIP(lst,l,r)
4 quicksortIP(lst,l,i)
5 quicksortIP(lst,i+1,r)
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 14 / 57
Suchen Heaps
Die Heap-Struktur
Ein Max-Heap ist . . .
. . . ein fast vollstandiger Binarbaum.
Max-Heap-Eigenschaft: Der Schlussel eines Knotens ist großer als dieSchlussel seiner beiden Kinder
Ein Max-Heap:23
18
19
21
9 7 5
3 642
Ein Min-Heap:
23
71
64
13
3829 98
3995 33 77 76 82 99
Der Max-Heap kann reprasentiert werden als:
[None,23,18,21,9,7,19,5,2,4,3,6]
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 15 / 57
Suchen Heaps
Heap – Aufgaben Implementierung
Aufgabe 9
1 Implementieren Sie die Funktion leftChild(heap,i), die den Wertdes linken Kindes von heap[i] zuruckgibt. Gibt es kein solches, sollNone zuruckgeliefert werden.
2 Implementieren Sie die Funktion rightChild(heap,i) entsprechend.
3 Implementieren Sie eine Funktion father(heap,i), die als Argumenteinen Heap heap und einen Index i ubergeben bekommt und denWert des Vaters von heap[i] zuruckliefert.
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 16 / 57
Suchen Heaps
Heaps – EinfugenFur viele Anwendungen wichtig: Effizientes Extrahieren des großten(kleinsten) Elements.Optimal dafur: Heaps!
Einfugen:
23
71
64
13
3829 98
3995 33 77 76 82 47
47
98
23
71
64
13
3829
3995 33 77 76 82 98
64
4723
71
13
3829
3995 33 77 76 82
Aufgabe 10
Vervollstandigen Sie den folgenden Code zur Implementierung derEinfuge-Operation in Heaps.
1 def insertH(heap, x):
2 heap.append(x)
3 ...
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 17 / 57
Suchen Heaps
Heaps – Min-Extrakt
72
72
29
72
72
2. 3.
4. 5.
1.
38
47
23
64
827639773395
95 33 76 82
71
3977
713829
23 47
64 29
95 33 77 39 76 82
7138
47
64
23
95
33
29
38
3977 76 82
71
47
64
23
95 33 77 39 76 82 72
713829
23 47
64
13
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 18 / 57
Suchen Heaps
Heaps – Min-Extrakt-Implementierung
1 def minExtrakt(heap):
2 returnVal=heap[1]
3 n=len(heap)-1
4 heap[1]=heap[n] # letztes Element an die Wurzel
5 del(heap[n])
6 n-=1 # n soll weiterhin auf das letzte Element zeigen
7 i=1
8 while i<=n/2:
9 j=2*i
10 if j<n and heap[j]>heap[j+1]: j+=1 # waehle kleineres der beiden Kinder
11 if heap[i]<=heap[j]: break
12 heap[i],heap[j]=heap[j],heap[i]
13 i=j
14 return returnVal
Laufzeit: O(log n)
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 19 / 57
Suchen Heaps
Heaps – build-Heap-Implementierung
Hintere Halfte der Liste (also lst[len(lst)/2:]): Sammlung vonlen(lst)/2 Heaps;
noch uber den vorderen Teil der Liste laufen und alle verletztenHeap-Bedingungen wiederherstellen.
1 def buildHeap(lst): # Es muss lst[0]==None gelten
2 for i in range(len(lst)/2,0,-1):
3 minHeapify(lst,i)
Laufzeit: O(n)
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 20 / 57
Suchen Heaps
Heaps – in Python
Die Standard-Modul heapq implementiert Heaps.
heapq.heapify(lst): Transformiert die Liste lst in-place inMin-Heap;
heapq.heappop(lst): Enfernt kleinestes Element aus Heap lst;
heapq.heappush(lst,x): Fugt ein neues Element x in Heap lst ein;
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 21 / 57
Suchen Skip-Listen
Skip-ListenSind ahnlich zu verketteten Listen, . . .
. . . außer, dass ein Element mehrere Vorwartszeiger haben kann.
Beispiel:
7 1319 30
32
34
39
91
936244
7681
Fur Skip-Liste muss gelten:
Wkeit, dass zufallig gewahlterEintrag i Vorwartszeiger hat:
pi−1 · (1− p)
Randomisierte Impl. ⇒
1 from random import random
2 p = ... # Wkeit mit 0<p<1
3 def randHeight():
4 i=0
5 while random()<=p: i+=1
6 return min(i,MaxHeight)
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 22 / 57
Suchen Skip-Listen
Skip-Listen – Implementierung
1 class SLEntry(object):
2 def __init__(self, key, ptrs=[], val=None):
3 self.key = key ; self.ptrs = ptrs ; self.val = val
4
5 class SkipList(object):
6 def __init__(self):
7 self.tail = SLEntry(Infty)
8 self.head = SLEntry(None,[self.tail]*(MaxHeight+1))
9 self.height = -1
⇒ Eine leere Skipliste hat ein
tail – Ein Ende mit key=∞head – Ein Kopf mit allen Vorwartszeigern auf tail
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 23 / 57
Suchen Skip-Listen
Skip-Listen – Suche
Suche nach einem Eintrag mit Schlussel key:
1 class SkiptList(object):
2 ...
3 def search(self, key):
4 x = self.head
5 for i in range(self.height,-1,-1):
6 while x.ptrs[i].key < key: x = x.ptrs[i]
7 x = x.ptrs[0]
8 if x.key == key: return x.val
9 else: return None
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 24 / 57
Suchen Skip-Listen
Skip-Listen – EinfugenWahle Hohe i durch Zufallsentscheidung (randHeight)Es mussen i Zeiger anderer Elemente
”umgebogen“ werden.
719 30
32
34
39
91
936244
7681
13
updatePtrs[3]
updatePtrs[2]
updatePtrs[1]
updatePtrs[0]
Der i-te Vorwartszeiger von updatePtrs[i] muss”umgebogen“ werden.
91
9381
719 30
32
34
39 6244
76
1379
Aufgabe 11
Implementieren Sie eine Methode insert(key,val) der Klasse SkipList
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 25 / 57
Suchen Skip-Listen
Skip-Listen – Aufgaben (1)
Aufgabe 12
Implementieren Sie die Funktion __str__, so dass Skip-Listenfolgendermaßen ausgegeben werden:
>>> print skiplist
>>> [ (30|1), (33|4), (40|3), (77|1), (98|1), (109|1), (193|3) ]
Ausgegeben werden soll also der Schlussel jedes Elements zusammen mitder Hohe des Elements.
Aufgabe 13
1 Schreiben Sie eine Methode keys(), die eine Liste der in derSkip-Liste gespeicherten Schlusselwerte zuruckliefert.
2 Schreiben Sie eine Methode vals(), die eine Liste der in derSkip-Liste gespeicherten Werte zuruckliefert.
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 26 / 57
Suchen Skip-Listen
Skip-Listen – Aufgaben (2)
Aufgabe 14
Oft wird eine effiziente Bestimmung der Lange einer Skip-Liste benotigt.Erweitern Sie die Klasse SkipList um ein Attribut length, passen Sieentsprechend die Methoden insert und delete an und geben Sie eineImplementierung der Methode __len__ an, so dass die len-Funktion aufSkip-Listen anwendbar ist.
Aufgabe 15
1 Schreiben Sie eine Funktion numHeights(h), die die Anzahl derElemente mit Hohe n zuruckliefert.
2 Schreiben Sie eine Funktion avgHeight(s), die die durchschnittlicheHohe eines Elementes der Skip-Liste s berechnet.
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 27 / 57
Suchen Bloomfilter
Bloomfilter – Grundlegendes
Sehr platz- und zeiteffiziente Moglichkeit des Membership-Tests.
Bloomfilter sind probabilistisch: Moglichkeit falsch-positiverAntworten.
I Datensatz in Bloomfilter ⇒ Antwort immer korrekt!I Datensatz nicht in Bloomfilter ⇒ Antwort nicht immer korrekt!
Eine Anwendung – unter vielen:
Speicher
Bloomfilter
samerlang-
w ∈ S?
nein
x ∈ S?
ja
ja
y ∈ S?
ja nein
z ∈ S?nein
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 28 / 57
Suchen Bloomfilter
Bloomfilter – Funktionsweise
Bsp:h0(eine) = 3, h0(Einfuhrung) = 1, h0(Informatik) = 6h1(eine) = 1, h1(Einfuhrung) = 8, h1(Informatik) = 7
Einfugen voneine
falsefalsefalsefalsefalsefalsefalse false false false0 1 2 3 4 5 6 7 8 9
falsefalsefalsefalsefalsefalse false0 1 2 3 4 5 6 7 8 9
true true true
falsefalsefalsefalsefalsefalsefalse false0 1 2 3 4 5 6 7 8 9
true true
Einfugen vonEinfuhrung
falsefalsefalsefalse false0 1 2 3 4 5 6 7 8 9
true true truetrue true
Einfugen vonInformatik
=h1(
eine
)
=h0(
eine
)
=h0(
Einfuhrung
)
=h1(
Einfuhrung
)
=h0(
Informatik
)
=h1(
Informatik
)
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 29 / 57
Suchen Bloomfilter
Bloomfilter – Implementierung
1 class BloomFilter(object):
2 def __init__(self, h, m):
3 self.k = len(h) ; self.h = h
4 self.A = [False]*m
5 self.m = m
6
7 def insert(self,x):
8 ... # Siehe Aufgabe
9 def elem(self,x):
10 ... # Siehe Aufgabe
Aufgabe 16
Implementieren Sie insert und elem.
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 30 / 57
Suchen Suchmaschinen
Suchmaschinen
Aufbau einer Suchmaschine
IndexCrawler SuchanfrageBearbeitung
Indexer GUI
Web
Dateisystem
Datenbank
Der invertierte Index
. . . das”Herz“ jeder Suchmaschine!
HashtabelleHeap
HeapsortHornerschema
Insertion Sort
. . .
. . .
Liste aller Worter
[430,102,344,982, ...]
[101,72,...]
[10,...]
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 31 / 57
Suchen Suchmaschinen
Implementierung
1 class Index(object):
2 def __init__(self, path=''):3 self.docId = 0
4 self.ind = {}5 self.docInd = {}6 if path!='': self.crawl(path)
1 def crawl(self, path):
2 def tupl(x,y): return (x,y)
3 for dirpath, dirnames, filenames \
4 in os.walk(path):
5 for file in filenames:
6 f = os.path.join(dirpath, file)
7 if isTxt(f):
8 self.addFile(f)
1 def addFile(self, file):
2 def tupl(x,y): return (x,y)
3 self.docInd[self.docId] = file
4 fileHandle = open(file)
5 fileCont = fileHandle.readlines() ; fileHandle.close()
6 fileCont = map(tupl, xrange(0,len(fileCont)), fileCont)
7 words = [(word.lower(),pos) for (pos,line) in fileCont
8 for word in line.split()
9 if len(word) >=3 and word.isalpha() ]
10 for word,pos in words: self.toIndex((word,pos), self.docId)
11 self.docId+=1
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 32 / 57
Suchen Suchmaschinen
Aufgaben
Aufgabe 17
Implementieren Sie die fehlende Methode toIndex((word,pos),docId)
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 33 / 57
Graphen Grundlagen
Reprasentation von Graphen
Der folgende Graph . . .
52
3 4
1 mit:
G = (V ,E ) mitV = {1, 2, 3, 4, 5},E = {(1, 2), (2, 2), (2, 3), (1, 3), (1, 4), (3, 4), (4, 5)}
. . . kann reprasentiert werden als . . .
Adjazenzmatrix0 1 1 1 00 1 1 0 00 0 0 1 00 0 0 0 11 0 0 0 0
Adjazenzliste
{2, 3, 4}{2, 3}{4}{5}{1}
12345
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 34 / 57
Graphen Grundlagen
Reprasentation in Python
1 class Graph(object):
2 def __init__(self,n):
3 self.vertices = []
4 self.numNodes = n
5 for i in range(0,n+1):
6 self.vertices.append({})
self.vertices ist die Adjazenzliste...
. . . deren Eintrage dict-Objekte sind . . .
. . . die adjanzente Knoten (inkl. evtl. Gewichte) enthalten.
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 35 / 57
Graphen Grundlagen
Wichtige Methoden (1)
Aufgabe 18
Implementieren Sie die Graph-Methoden addEdge, isEdge, G, V, E undfullen sie hierzu die Lucken in folgendem Listing:
1 class Graph(object):
2 ...
3 def addEdge(self,i,j,weight=None):
4 ...
5 def isEdge(self,i,j):
6 ...
7 def G(self,i):
8 ...
9 def V(self):
10 ...
11 def E(self):
12 ...
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 36 / 57
Graphen Grundlagen
Wichtige Methoden (2)
Aufgabe 19
Erweitern Sie die Klasse Graph um die Methode Graph.w(i,j), die dasGewicht der Kante (i, j) zuruckliefert (bzw. None, falls die Kante keinGewicht besitzt).
Aufgabe 20
Erweitern Sie die Klasse Graph um die folgenden Methoden:
1 Eine Methode Graph.isPath(vs), die eine Knotenliste vs ubergebenbekommt und pruft, ob es sich hierbei um einen Pfad handelt.
2 Eine Methode Graph.pathVal(vs), die eine Knotenliste vs ubergebenbekommt. Handelt es sich dabei um einen gultigen Pfad, so wird der
”Wert“ dieses Pfades (d. h. die Summe der Gewichte der Kanten des
Pfades) zuruckgeliefert. Andernfalls soll der Wert ∞ (in Python:float('inf')) zuruckgeliefert werden.
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 37 / 57
Graphen Kurzeste Wege
Algorithmus von Warshall
Berechnet die kurzesten Wege zwischen allen Knotenpaaren.
Berechnungsschema:1 Berechne W0: alle kurzesten Wege mit keinen
”Zwischenknoten“
2 Aus Wk−1 berechnet Wk : alle kurzesten Wege mit Zwischenknoten∈ {1, . . . , i}
3 Losung: Wn
Schritt von Wk−1 nach Wk :
Pfad mit Knoten aus {1, . . . , k − 1}
Pfad mit Knoten aus {1, . . . , k}
i j
k
Es gilt:
Wk [i , j ] := min{ Wk−1[i , j ], Wk−1[i , k] + Wk−1[k , j ] }
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 38 / 57
Graphen Kurzeste Wege
Warshall Implementierung
1 def warshall(graph):
2 n = graph.numNodes+1
3 W = [ [graph.w(i,j) for j in graph.V()] for i in graph.V() ]# W_0
4 ...
W: Adjazenzmatrix des Graphen, also W0.
Aufgabe 21
Vervollstandigen Sie die Implementierung des Warshall-Algorithmus, d. h.ersetzen sie die ...-Stelle durch Code, der Sukzessive W1, W2, . . . , Wn
berechnet.
Aufgabe 22
Was ist die Laufzeit des Warshall-Algorithmus? D. h. wie vieleBerechnungsschritte – in der O-Notation – benotigt derWarshall-Algorithmus zur Berechnung der kurzesten Wege eines Graphenmit n Knoten?
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 39 / 57
Graphen Kurzeste Wege
Der Dijkstra-Algorithmus
Berechnet nicht alleAbstande zwischen allenKnoten, sondern . . .
. . . berechnet – ausgehendvon einem Knoten v – dieAbstande l[u] (Lange derkurzesten Wege) zu allenKnoten u∈ V .
Edsger Dijkstra (1930 - 2002)
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 40 / 57
Graphen Kurzeste Wege
Der Dijkstra-Algorithmus – Funktionsweise
Dijkstra ist greedy:
Knoten werdensukzessive
”abgehakt“:
I Es kommt immerderjenige Knotenan die Reihe, dermomentan dengeringsten l-Werthat.
I Es wird versucht,die Abstande allerseiner Nachbarn zuverbessern.
W = {a, b, c , d , e, f , g , u}
l [u]=0
a
b d
c
e
u f
g
4
2
1
2
53
5
82
11
3 4
10
7
W = {a, b, c, d , e, f , g}
l [c]=11 l [u]=0 l [f ]=2
l [e]=7 l [g ]=5l [d ]=4
a
b d
c
e
u f
g
4
2
1
2
53
5
82
11
3 47
10
l [c]=11 l [u]=0 l [f ]=2
l [e]=7
W = {a, b, c , d , e, g}l [g ]=3l [d ]=4
a
b d
c
e
u f
g
4
2
1
2
53
5
82
11
3 47
10
l [c]=11 l [u]=0 l [f ]=2
l [e]=7 l [g ]=3
W = {a, b, c , d , e}l [d ]=4
a
b d
c
e
u f
g
4
2
1
2
53
5
82
11
3 47
10
l [u]=0 l [f ]=2
l [g ]=3l [e]=6
l [c]=9
W = {a, b, c , e}l [b]=14 l [d ]=4
a
b d
c
e
u f
g
4
2
1
2
53
5
82
11
3 47
10
l [u]=0 l [f ]=2
l [g ]=3l [e]=6
l [c]=9l [a]=11
l [b]=13
W = {a, b}l [d ]=4
a
b d
c
e
u f
g
4
2
1
2
53
5
82
11
3 47
10
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 41 / 57
Graphen Kurzeste Wege
Der Dijkstra-Algorithmus – Implementierung
1 def dijkstra(u,graph):
2 n = graph.numNodes
3 l = { u : 0 } ; W = graph.V()
4 F = []; k = {}5 for i in range(0,n):
6 lv,v = min([ (l[lk],lk) for lk in l.keys() if lk in W ])
7 W.remove(v)
8 if v!=u: F.append(k[v])
9 ...
10 return l,F
W: Menge der noch zu bearbeitenden Knoten
k[v]: Vorgangerknoten von v auf kurzestem Weg nach v (vorlaufig).
F: Vorgangerknoten von v auf kurzestem Weg nach v (final).
Aufgabe 23
Vervollstandigen Sie die Implementierung des Dijkstra-Algorithmus.
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 42 / 57
Graphen Minimaler Spannbaum
Minimaler Spannbaum – Kruskal-Algorithmus
Spannbaum = Teilgraph GT = (VT ,ET ) eines ungerichtetenzusammenhangenden Graphen G = (V ,E ), der ein Baum (alsokreisfrei und zusammenhangend) ist.
a
b
c
d
e
f
g
ha
b
c
d
e
f
g
ha
b
c
d
e
f
g
ha
b
c
d
e
f
g
h a
b
c
d
e
f
g
h
Anwendungen:I Moglichst preisgunstiges zusammenhangiges Netzwerk.I Vermeidung von redundanten Sendepfaden.
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 43 / 57
Graphen Minimaler Spannbaum
Kruskal-Algorithmus – Funktionsweise
Algorithmus ist greedy:
In jedem Schritt wird immer genau eine Kante hinzugenommen, furdie gilt:
I minimales Gewicht + ohne dass Kreis entsteht.
. . . solange, dass bis dies nicht mehr geht.
⇒ Minimaler Spannbaum gefunden.
1
3
22
2
4
5
6
7
8
9
3
31
2
43 1
1
1
5
1
1
3
22
2
4
5
6
7
8
9
3
31
2
43 1
1
1
5
1
1
3
22
2
4
5
6
7
8
9
3
31
2
43 1
15
1 1
1
3
22
2
4
5
6
7
8
9
3
31
2
43
15
1 1
11
3
22
2
4
5
6
7
8
9
3
3
2
43
15
1 1
1
1
1
3
22
2
4
5
6
7
8
9
3
3
2
43
15
1 1
1
1
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 44 / 57
Graphen Minimaler Spannbaum
Kruskal-Algorithmus – Implementierung
1 def kruskal(graph):
2 allEdges = [(graph.w(i,j),i,j) for i,j in graph.E_undir()]
3 allEdges.sort(reverse=True) # absteigend
4 spannTree = []
5 while len(spannTree) < len(graph.V())-1 and allEdges!=[]:
6 (w,i,j) = allEdges.pop()
7 if not buildsCircle(spannTree,(i,j)):
8 spannTree.append((i,j))
9 return spannTree
Aber:
1 Sortieren aller Kanten:O(|E | log |E |) ⇒ ineffizienter als Verwendungeines Heap: O(|E |+ |V | log |E |)
2 Implementierung von buildsCircle?
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 45 / 57
Graphen Minimaler Spannbaum
Union-Find-Datenstruktur
Bietet effiziente Implementierungder Mengenoperationen . . .
1 . . .”Vereinigung“ (zweier Mengen)
union(x,y) – x und y eindeutigeReprasentanten einer Menge
2 . . .”Suche“ eines Elementes in
einer Menge –find(x) – liefert eindeutigenReprasentanten der Menge, die x
enthalt.
Gleichzeitig: Effizienter Test, obdurch das Hinzufugen einer Kante(i , j) ein Kreis entsteht.
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 46 / 57
(f):find(1) ∪ find(3)
(g):find(2) ∪ find(1)
(h):find(6) ∪ find(7)
(d):find(4) ∪ find(8)
(c):find(7) ∪ find(9)
(a):find(3) ∪ find(6)
(b):find(8) ∪ find(9)
(e):find(5) ∪ find(6)
8
9
4
7
3
6
5
1
2
1 2 5
3
6
7
8
9
4
7
8
9
4
3
6
5
12
7
8
9
4
3
6
5
12
1 2 3 4 5 6 7 8 9
1 2 3 4 5 7 8 9
6
1 2 3 4 5 7 8
6 9
1 2 3 4 5
6
7
8
9
1 2 3
6
5 7
8
9
4
Graphen Minimaler Spannbaum
Union-Find im Kruskal-Algorithmus
Kante {i , j} hinzufugen?
Zwei Falle:1 Falls find(i)==find(j):
I Nicht hinzufugen!I Denn: i und j befinden sich in derselbsen Zusammenhangskomponente.⇒ i und j verbunden.⇒ Es wurde ein Kreis entstehen.
2 Falls find(i)!=find(j):I Hinzufugen!I Denn: i und j bisher nicht verbunden.⇒ Es entsteht kein Kreis
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 47 / 57
Graphen Minimaler Spannbaum
Union-Find Implementierung
self.parent: Speichert furjeden Knoten den Elternknoten.
self.parent[i]== 0 gdw. i hatkeinen Elternknoten.
find(x): Liefert Wurzel desBaumes, der x enthalt.
union(x,y): fugt zwei Baumezusammen, indem die Wurzeldes einen Baumes (der y
enthalt) als Kind unter dieWurzel des anderen Baumes(der x enthalt) gehangt wird.
1 class UF(object):
2 def __init__(self,n):
3 self.parent = [0]*n
4
5 def find(self,x):
6 while self.parent[x] > 0:
7 x = self.parent[x]
8 return x
9
10 def union(self,x,y):
11 self.parent[y] = x
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 48 / 57
Graphen Minimaler Spannbaum
Union-Find – Aufgaben/Verbesserungen
Aufgabe 24
Implementieren Sie fur die Klasse UF die str-Funktion, die ein Objekt derKlasse in einen String umwandelt. Beispiel-Ausgabe:
>>> uf = UF(10)
>>> uf.union(1,2) ; uf.union(1,3) ; uf.union(5,6) ; uf.union(8,9)
>>> str(uf)
>>> '{1, 2, 3} {4} {5, 6} {7} {8, 9} '
Eine sehr nutzliche Verbesserung: Balancierung!
Aufgabe 25
Verbessern Sie die Union-Find-Impl. indem Sie auf die Balancierung derBaume achten. find(x) sollte nur dann als Kind unter die Wurzel vonfind(y) gehangt werden, wenn Hohe(find(x)) < Hohe(find(y));andernfalls: find(y) unter die Wurzel von find(x) hangen.Tipp: (Negative) Hohe in der Wurzel speichern.
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 49 / 57
Graphen Minimaler Spannbaum
Union-Find – Aufgaben/VerbesserungenEine weitere sehr nutzliche Verbesserung: Pfad-Komprimierung!
Aufgabe 26
find(x) findet immer den Pfad von x zur Wurzel.
⇒ fuge danach Direktkante von x zur Wurzel ein.. . . und auch Direktkanten fur alle Knoten auf dem Pfad.
Implementieren Sie diese Verbesserung.
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 50 / 57
Graphen Minimaler Spannbaum
Kruskal-Algorithmus – Aufgabe
Aufgabe 27
Implementieren Sie den Kruskal-Algorithmus unter Verwendung derUnion-Find-Datenstruktur.
Aufgabe 28
Man kann den minimalen Spannbaum auch finden, indem man genauumgekehrt wie der Kruskal-Algorithmus vorgeht: Man beginne mit allen imGraphen enthaltenen Kanten und entfernt Kanten mit dem momentanhochsten Gewicht – nur dann aber, wenn man dadurch den Graphen nichtauseinander bricht.
Geben Sie eine Implementierung des”umgekehrten“ Kruskal-Algorithmus
an.
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 51 / 57
Schwere Probleme Losung des Traveling Salesman Problems
Das TSP-Problem
TSP = Travelling SalesmanProblem.
Gegeben:n Stadte
Gesucht:Kurzeste Rundtour, die jedeStadt genau einmal besucht.
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 52 / 57
Berlin
Hamburg
Bremen
HannoverBielefeld
DortmundBochumEssenDuisburgDüsseldorfWuppertal
KölnBonn
Frankfurt am Main
Mannheim
Stuttgart
München
Nürnberg
LeipzigDresden
Berlin
Losung des TSP fur die 20großten Deutschen Stadte.
Schwere Probleme Losung des Traveling Salesman Problems
TSP-Losung durch Ausprobieren
Losung des TSP = Permutation der n Stadte.
⇒ Durchprobieren aller Permutationen perms(graph.V())
Aufgabe 29
Implementieren Sie den Brute-Force-Losungsansatz”Durchprobieren aller
Permutationen“, um die optimale Losung des TSP zu finden undvervollstandigen Sie hierzu den folgenden Code:
1 def TSPBruteForce(graph):
2 nodeList = graph.V()[1:]
3 return ...
Tipp: Verwenden Sie graph.pathVal um die Lange eines Pfades zubestimmen.
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 53 / 57
Schwere Probleme Losung des Traveling Salesman Problems
TSP-Losung durch Dynamische Programmierung
Furs TSP gilt das sog. (Bellmannsche) Optimalitatsprinzip:
Eine optimale Losung setzt sich zusammen aus . . .
. . .”kleineren“ optimalen Losungen.
⇒ Losung durch Dynamische Programmierung moglich:
Zuerst: Losungen der”kleinen“ Teilprobleme berechnen . . .
. . . und Zwischenergebnisse in Tabelle speichern.
Bei Berechnung der großeren Teilprobleme: Auf Tabelle zuruckgreifen.
Furs TSP gilt:
T (i ,S): Wert der kurzesten Tour, startend bei Knoten i , die alleKnoten aus S genau einmal besucht und bei Knoten 1 endet
Dann gilt:
T (i ,S) = minj∈S
(w(i , j) + T (j , S \ {j})
)T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 54 / 57
Schwere Probleme Losung des Traveling Salesman Problems
TSP-Losung durch Dynamische Programmierung (2)Die Formel
T (i ,S) = minj∈S
(w(i , j) + T (j , S \ {j})
)Entspricht in Python (T ist Dict-Objekt):
T[(i,S)] = min( graph.w(i,j)+T[(j,diff(S,[j]))] for j in S)
1 def tsp(graph):
2 n = graph.numNodes
3 T = {}4 for i in range(1,n+1): T[(i,())] = graph.w(i,1)
5 for k in range(1,n-1):
6 ...
Aufgabe 30
Vervollstandigen Sie die Implementierung und ersetzen Sie die ... durchden entsprechenden Code.
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 55 / 57
Schwere Probleme Greedy-Heuristiken zur Losung des TSP
Nearest-Neighbor-Heuristik
Von der aktuellen Stadt aus . . .
. . . wahlt man einfach immer die nachste aus.
Aufgabe 31
Implementieren Sie die Nearest-Neighbor-Heuristik fur das Traveling-Salesman-Problem und testen Sie diese durch Berechnung der kurzestenTour durch die . . .
1 . . . großten 20 deutschen Stadte.
2 . . . großten 40 deutschen Stadte.
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 56 / 57
Schwere Probleme Greedy-Heuristiken zur Losung des TSP
Insertion-Heuristiken
Man beginnt mit sehr kurzer (2 Stadte) Tour . . .
. . . und fugt sukzessive weitere Knoten hinzu.
Folgende Strategien:
”Nearest Insertion“: Als nachtes wird derjenige Knoten hinzugefugt,
der zur momentanen Tour den geringsten Abstand hat.
”Farthest Insertion”: Als nachtes wird derjenige Knoten hinzugefugt,der zur momentanen Tour den großten Abstand hat.
”Random Insertion”: Als nachtes wird zufallig ein noch nicht in derTour befindlicher Knoten zur Tour hinzugfugt.
Aufgabe 32
Implementieren Sie die Nearest/Farthest/Random-Insertion-Heuristik.
T. Haberlein HS AlbSig Algorithmik mit Python Leipzig, 04.04.2011 57 / 57