Algorithmen und Datenstrukturen - Universität Düsseldorf: Informatik

Werbung
Algorithmen und Datenstrukturen
Prof. Martin Lercher
Institut für Informatik
Heinrich-Heine-Universität Düsseldorf
Teil 11
10
Suche in Graphen
Designtechniken
für Algorithmen
Version
vom
Januar 2017
Version
vom
13.12.
Dezember
2016
FortsetzungVorlesungvom13.Januar
SucheimTelefonbuch
Exhaus'veSuche
•  GehevonA-ZalleEinträgedurch
•  O(N)
BinäreSuche
•  SchlagedasTelefonbuchinderMiHeauf
Sindwirzuweitodernochnichtweitgenug?
GeheindieMiHederrelevantenHälLe
…
•  O(log(N))
Interpola'ons-Suche
•  O(log(log(N))imDurchschniH
Design-Techniken
•  VieleAlgorithmenbenutzenähnlicheIdeen/Konzepte
•  Hier:zunächsteinkurzerÜberblick
•  Ziel:lernezuerkennen,obeinneuesProblemdurcheineStandard-Technik
gelöstwerdenkann
Beispielproblem:
WoinmeinerWohnungliegtdasklingelndeHandy?
Exhaus]veSuche(BruteForce)
Design-Idee:
UntersuchenacheinanderjedemöglicheAlterna]ve.
•  Ignoriertevt.verfügbarezusätzlicheInforma]onen(z.B.dieRichtung,aus
derdasKlingelnkommt)
•  EinfachstesVerfahren(Implemen]erung)
•  LangsamstesVerfahren(Komplexität)
•  VorhandeneLösungwirdgaran]ertgefunden
•  FürsehrkleineProblemerealis]sch
Branch-and-Bound
Abgekürzteexhaus]veSuche.
Design-Idee:
VerfolgeSuchpfadenursolange,bisklarist,dasssienichtzumErgebnis
führen.
Beispiel:wenndasKlingelnvonObenkommt,brichdieSucheimKellerab.
GierigeAlgorithmen(Greedyalgorithms)
Design-Idee:
BeiderWahlzwischenAlterna]ven:wählediejenige,die(nachkurzer,
einfacherAbwägung)alsdievielversprechendsteerscheint.
Beispiel:laufedirektinRichtungdesKlingeltons.
Aber:waswenndasHandyimGartenliegtundichhöredasKlingeln
durch’sFenster?
•  SehrschnellesVerfahren
•  Problem:der‘vielversprechendste’Pfadkannlangfris]gderfalschesein
(lokaleOp]ma)
DynamischeProgrammierung
Design-Idee:
Wenniden]scheTeilproblemeimmerwiedergelöstwerdenmüssen:
recycling(miteinerTabelle).
Beispiel:Steinchen-Spiel.
•  ZweiStapelmitje10Steinen.
•  DieSpielernehmenabwechselndentwedereinenSteinoderzweiSteine(je
einemvonjedemStapel).
•  DerSpielerderdenletztenSteinnimmtgewinnt.
Fragen:
•  GibteseinesichereGewinnstrategie?
•  WelcherSpielergewinnt?
DynamischeProgrammierung
0
0
1
2
3
4
5
6
7
8
9
1
W
W
W
2
3
4
5
6
7
8
9
10
Divide&Conquer(Teile&Herrsche)
Design-Idee:
SpalteursprünglichesProbleminTeilprobleme,lösejedesfürsich,setze
ErgebnissezuGesamtlösungzusammen.
Beispiele:
•  Quicksort
•  Mergesort
MachineLearning(MaschinellesLernen)
Design-Idee:
BildeAlgorithmusaufgrundvonMusternausBeispieldatensätzen.
Beispiel:
FühreBuchüberdieAblagestelledesHandys.Suchezuerstamhäufigsten
Platz(z.B.80%Küche),dannamzweithäufigstenPlatz(12%Wohnzimmer),
etc.
Wannkannman
welchesDesignverwenden?
Exhaus]veSuche
-immer,istaberineffizient-
Wannkannman
welchesDesignverwenden?
GierigeAlgorithmen
Greedy-ChoiceEigenschaL
Die‘Greedy-Choice’EigenschaLbesagt,dasslokalop]maleEntscheidungen
(=greedychoices)zueinemglobalenOp]mumführen.
IndiesemFallführtdergierigeAlgorithmuszueinemexaktenErgebnis.
Wannkannman
welchesDesignverwenden?
Divide&Conquer
Divide-and-Conquer
Einedivideandconquer(TeileundBeherrsche)Methodeeignetsichfür
Probleme,dierekursivinTeilproblemezerlegtwerdenkönnen(bisdie
Teilproblemesoeinfachsind,dasssiedirektgelöstwerdenkönnen).
Divide-and-Conquerfunk]oniertdanngut,wenndieAnzahlderTeilprobleme
injedemSchriHkleinbleibtundwenndieZusammensetzungderTeillösungen
einfachist.
Wannkannman
welchesDesignverwenden?
DynamischeProgrammierung
Op]maleSubstruktur
EinProblemhateineop]maleSubstrukturgenaudann,wenneineop]male
LösungdesProblemsop]maleLösungenvonTeilproblemenenthält.
WenneinProblemop]maleSubstrukturhat,könnteessichfürLösungdurch
dynamischeProgrammierungeignen.
ÜberlappendeTeilprobleme
UmfürdynamischeProgrammierunggeeignetzusein,mussderRaumder
Teilproblemekleinsein:einrekursiverAlgorithmuswürdedasselbe
Teilproblemimmerwiederlösen.
DieGesamtzahlderTeilproblemeisttypischerweisepolynomialinder
Eingabegröße.
Hinweis
WenneinrekursiverAlgorithmusimmerneue(bisherungelöste)Teilprobleme
erzeugt,dannistvermutlicheineDivide-and-ConquerStrategiebesser
geeignet.
Vorlesungvom17.Januar
VERSCHIEDENEALGORITHMENFÜR
DASSELBEPROBLEM
21
Ak]enproblem
Gesucht:BesterKauf-undVerkaufstagfüreineAk]e
Gegeben:KursänderungenproTag
Problem:FindeeinIndex-PaarKV:=(i,j)ineinemArraya[1..n]vonganzen
Zahlen,fürdasf(i,j)=ai+ai+1+…+ajmaximalist.
AlsRechenschriHezählenarithme]scheOpera]onenundVergleiche.
22
BruteForce(Naiv,exhaus]veSuche)
Eswirdf(i,j)füralleiundjberechnetunddarausdermaximaleWert
bes]mmt.ZurBerechnungvonf(i,j)benö]genwirgenauj-iAddi]onen.Wir
beginnenmitOffensichtlichgenügenzurBerechungvongenau
Addi]onen.DerAlgorithmusstartetmitKV=f(1,1)undaktualisiertKVwenn
nö]g.
Laufzeit:
T (n) ∈ Θ(n 3 )
23
DynamischeProgrammierung(Naïve++)
DernaiveAnsatzberechnetvieleTeilsummenmehrfach,z.B.a1+a2für
f(1,2),f(1,3),…f(1,n),alson-1mal.DurchWiederverwendungder
TeilsummensspartmanAufwand:
f(i,j+1)=f(i,j)+aj+1
DamitkönnenalleWertef(i,j)fürfestesiingenau(n-i)SchriHenbes]mmt
werden.
Laufzeit:
T (n) ∈ Θ(n 2 )
24
Divide&Conquer
M M+1
DiegrößteTeilfolgeliegtentweder:
•  imlinkenTeil;
•  imrechtenTeil;
•  oderteilslinks,teilsrechts
Alslinkes(rechtes)RandmaximumbezeichnenwirdieSummederTeilfolge
al,...,aM(aM+1,...,ar),fürdiedieSummemaximalwirdunterallen
Teilfolgen,diemitl∈[1,M]beginnen(mitr∈[M+1,n]enden).
25
AufwandfürdieBes]mmungderRandmaxima
•  links:M−1Addi]onenundebensovieleVergleiche
•  rechts:(n−M−1)Addi]onenundebensovieleVergleiche
•  Summe:2·n−2SchriHe
DieRandmaximaseienrlundrr.
FallsdiemaximaleTeilfolgedenRandaMumfaßt,soistal+…+areine
maximaleTeilfolgemitTeilsummerl+rr.
26
Divide&Conquer
Divide
LöseTeilproblemea1,...,aMundaM+1,...,anrekursiv.
DieMaximaseienslundsr
Merge
DiemaximaleTeilsummeergibtsichnunals
max{sl,sr,rl+sr}
27
sieheVorlesungTeil2:
Master-Theorem (Hauptsatz der Laufzeitfunktionen)
Satz
Seien a, b, k 2 N, mit a 1, b 2 und k 0.
Sei die Laufzeit eines Algorithmus durch folgende Rekurrenz-Relation
beschrieben:
⇣n⌘
T (n) = aT
+ f (n)
b
mit
f (n) 2 ⇥(nk ).
Dann gilt:
T (n) 2 ⇥(nk )
wenn
T (n) 2 ⇥(nk log (n)) wenn
T (n) 2 ⇥(nlogb (a) )
wenn
a < bk
a = bk
a > bk
Gilt genauso auch für O (mit T (n)  ...) und ⌦ (mit T (n)
...).
Beweis.
...mit Analysis, siehe z.B. Jonsonbaugh and Schaefer S. 60-65...
30 / 94
Aufwand
Sein=2k,undwirteilenjeweilsinderMiHe,M=n/2.
T (n) = 2T (n / 2) + 2n ⇒ T (n) ∈Θ(n log(n))
mitdemMaster-Theorem
29
Scanline
bismax
scanmax
WirlaufenmitderScanlinievonlinksnachrechtsundmerkenunsdabeizweiZahlen:
bisMax=diegrößtebishergeseheneTeilfolge
ScanMax=daslinkeRandmaximumderScanlininie
while(nächstesElementajexis]ert){
If(ScanMax+aj>0)
ScanMax=ScanMax+aj
else ScanMax=0
bisMax=max(bisMax,ScanMax)
}
Laufzeit:
T (n) ∈ Θ(n)
30
ZusammenfassungdesAk]enproblems
• 
• 
• 
• 
BruteForce
DynamischeProgr.
Divide&Conquer
Scanline
RechenschriSe:
31
Divide&Conquer
DieDivide&ConquerTechnik
aproblemofsizen
subproblem1
ofsizen/2
subproblem2
ofsizen/2
asolu'onto
subproblem1
asolu'onto
subproblem2
asolu'onto
theoriginalproblem
Divide&Conquer
DiewohlbekanntesteDesign-Strategie
1.  TeileeineInstanzdesProblemsin2odermehrkleinereInstanzen
2.  LösediekleinerenInstanzenrekursiv(oderdirekt,wennsiekleingenug
sind)
3.  ErhalteeineLösungfürdieursprünglicheProbleminstanzdurcheine
Kombina]onderLösungenderkleinerenInstanzen
•  OLkönnenDivide&ConquerAlgorithmenrekursivdefiniertwerden
(nichtimmernö]g!)
•  Eintop-downAnsatzzurProblemlösung
EinKachel-Problem
EinTrominoisteinObjektausdrei1x1Quadraten:
EinnxnBreH,demein1x1Feldfehlt(d.h.miteinerLücke)isteindefizientes
BreH.
GegebeneindefizientesnxnBreHmitn=2k,bedeckedasBreH–ohne
Überlappungen–mitTrominos.
2x2:
4x4:
EinKachel-Problem
LösungmitDivide&Conquer:
•  TeiledasnxnSpielbreHin4BreHermitn/2xn/2Feldern.
•  Einesder4TeilbreHerenthältdieLücke;LegeeinenTrominoindieMiHe,
sodassermitdenanderen3TeilbreHernüberlappt.
•  BetrachtedieFelderdiesesTrominosals“Lücken”–dannhatjedes
TeilbreHgenaueineLücke.
•  Lösealleviern/2xn/2Teilproblemerekursiv
•  Fürn=2istdieLösungtrivial(einTromino)–Rekursionsende.
KachelneinesdefizientenBreHsmitTrominos
Eingabe: n, a power of 2 (the board size);
L, the location of the missing square
tile(n,L) {
if (n == 2) {
// the board is a tromino T
tile with T // in the right orientation vs. L
return
}
divide the board into four n/2 × n/2 subboards
place 1 tromino centrally, making all subboards deficient
let m1,m2,m3,m4 be the locations of the missing squares
tile(n/2,m1)
tile(n/2,m2)
tile(n/2,m3)
tile(n/2,m4)
}
Laufzeit?
Analyse
•  Annahme:‘]lewithT’undBerechnungvonmiinO(1)
•  DannistdieLaufzeitpropor]onalzurAnzahldergelegtenTrominos:
n2 − 1
= Θ(n 2 )
3
Realworld:DesignvonComputerchips
Mergesort
•  TeileArrayin2HälLen
–  TrivialfürLänge1
–  SonstRekursion
•  Merge(Verschmelze)diesor]ertenHälLen,indemPosi]onszeigerbeide
durchläuLundjeweilsdiekleinereZahlinHilfsarraykopiert.
AlgorithmusMergesort(F):
•  FallsFnureinElementenhält,gibFzurück
•  Divide:TeileFinzweigleichgroßeTeilfolgenF1undF2
•  Conquer:Mergesort(F1),Mergesort(F2)
•  Merge:VerschmelzeF1undF2
Closest-PairProblem
FindediezweiPunktemitgeringstemeuklidischemAbstand.
Closest-PairProblem:DivideandConquer
•  Bruteforce:vergleichejedenPunktmitjedemanderen
•  BeinPunkten:
n−1
∑k =
k=1
(n − 1)⋅ n
∈O(n 2 )
2
•  Divide&Conquer:O(nlogn)
Closest-PairProblem:DivideandConquer
•  Sor]erediePunktein1Dimension(x-Achse):O(nlogn)mitMergesort
•  Divide:
–  TeileinzweiHälLenundbes]mmeclosestpairinjederHälLe.
–  bei≤3Punkten:bes]mmeclosestpairdirekt
•  Conquer(ähnlichwieScanLine):
–  derkleinsteAbstandliegtlinks(δl)oderrechts(δr)
odererüberstreichtdieGrenze:dannliegenbeidePunktejeweilsim
Streifenmitmax.Abstandδ=min(δl,δr)
–  WennwirallePunkteimStreifenuntersuchen,sinddasimworstcase
n,alsoΩ(n2)Vergleiche!
–  Aber:wirmüssennurPunktevergleichen,diemaximaldenAbstandδ
aufdery-Achsehaben…
–  …unddassindmaximal8Punkte,denn:wärenineinemAchteldeszu
durchsuchendenRechteckszweiPunkte,wärederenAbstandmaximal
(Diagonale!):
⎛⎛ δ ⎞2 ⎛ δ ⎞2⎞
δ
+
=
<δ
⎜ ⎜⎝ 2 ⎟⎠ ⎜⎝ 2 ⎟⎠ ⎟
2
⎝
⎠
Closest-PairProblem:DivideandConquer
–  Aber:wirmüssennurPunktevergleichen,diemaximaldenAbstandδ
aufdery-Achsehaben…
–  …unddassindmaximal8Punkte,denn:wärenineinemAchteldeszu
durchsuchendenRechteckszweiPunkte,wärederenAbstandmaximal
(Diagonale!):
⎛⎛ δ ⎞2 ⎛ δ ⎞2⎞
δ
⎜ ⎜⎝ 2 ⎟⎠ + ⎜⎝ 2 ⎟⎠ ⎟ = 2 < δ
⎝
⎠
δ
δ
δ
43
Input Parameters: List of points p=p[1], …, p[n]
closest_pair(p) {
mergesort(p,1,n) // sort p by x-coordinate p[i].x
return rec_cl_pair(p,1,n)
}
// rec_cl_pair assumes that input is sorted by x-coordinate.
// At termination, the input is sorted by y-coordinate.
rec_cl_pair(p,i,j) {
if (j - i < 3) { // simple case, no further recursion:
mergesort(p,i,j) // sort by y-coordinate
// find the distance delta between a closest pair
delta = dist(p[i],p[i + 1]) // Euclidean distance
if (j - i == 1) // two points
return delta
// three points
if (dist(p[i + 1],p[i + 2]) < delta)
delta = dist(p[i + 1],p[i + 2])
if (dist(p[i],p[i + 2]) < delta)
delta = dist(p[i],p[i + 2])
return delta
}
...
...
}
// we only get here if n>3; recursion:
k = (i + j)/ 2
// division point
l = p[k].x
// x coordinate of p[k]
deltaL = rec_cl_pair(p,i,k)
deltaR = rec_cl_pair(p,k + 1,j)
delta = min(deltaL,deltaR)
// p[i], ... , p[k] is now sorted by y-coordinate, and
// p[k + 1], ... , p[j] is now sorted by y-coordinate.
merge(p,i,k,j) // the standard merge from mergesort
// p[i], ... , p[j] is now sorted by y-coordinate.
// store points in the vertical strip in v.
t = 0
for k = i to j
if (p[k].x > l - delta && p[k].x < l + delta) {
t = t + 1
v[t] = p[k]
}
// look for closer pairs in the strip by comparing
// each point in the strip to the next 7 points.
for k = 1 to t - 1
for s = k + 1 to min(t,k + 7)
delta = min(delta,dist(v[k],v[s]))
return delta
Analyse
Worst-caseLaufzeit:
•  Sor]erennachx-Koordinate:Θ(nlogn)mitMergesort
•  Sor]erennachy-Koordinate:Θ(nlogn)mitMergesort
•  LaufzeitderRekursionen:
Tn ≤ T⎢⎣n/2 ⎥⎦ + T⎢⎣(n+1)/2 ⎥⎦ + cn
fürn>3
=>O(nlogn)
Mul]plika]onganzerZahlen
Z=X*Y=O(1)imEinheitskostenmaß;
BeigroßenZahlenlogarithmischesKostenmaß(digits)besser!
SeidieLänge(digits)vonXundYjeweilsetwan.
StandardmethodeausderSchule:Θ(n2)
TeileX,YjeweilsinHälLenXLXR,YLYR
Bsp.:X=123|456,Y=789|123
Z=XY=XLYL106+(XLYR+XRYL)103+XRYR
Tn = 4Tn/2 + cn
⇒ Θ(n 2 )
Mul]plika]onganzerZahlen
TeileX,YjeweilsinHälLenXLXR,YLYR
Bsp.:X=123|456,Y=789|123
Z=XLYL106+(XLYR+XRYL)103+XRYR
WirbraucheneineMul]plika]onweniger!
XLYR+XRYL=(XL-XR)(YR-YL)+XLYL+XRYR
dieletztenbeidenTermewerdenohnehinberechnet!
Tn = 3Tn/2 + cn
⇒ Θ(n log2 3 ) ≈ Θ(n1.59 )
Strassen’s(1969)Matrixprodukt
SeienAundBzweinxnMatrizenmitn=2kundseiC=AB.
TeileAundBinje4n/2xn/2–Matrizen.
c00c01a00a01b00b01
=
c10c11a10a11b10b11
a00b00+a01b10
a00b01+a01b11
=
a10b00+a11b10
a10b01+a11b11
4(n/2)2Opera]onenzumVerknüpfenderTeillösungen,also
Tn = 8Tn/2 + cn 2
⇒ O(n 3 )
Strassen’s(1969)Matrixprodukt
c00c01a00a01b00b01
=
c10c11a10a11b10b11
m1+m4-m5+m7 m3+m5
=
m2+m4
m1+m3-m2+m6
m1=(a00+a11)*(b00+b11)
m2=(a10+a11)*b00
7 Multiplikationen!
m3=a00*(b01-b11)
18 Additionen (Θ(n2))
m4=a11*(b10-b00)
m5=(a00+a01)*b11
Tn = 7Tn/2 + cn 2
m6=(a10-a00)*(b00+b01)
log 7
⇒
Θ(n
m7=(a01-a11)*(b10+b11)
)
Vorlesungvom20.Januar
GierigeAlgorithmen
-GreedyAlgorithms-
Op]mierungsproblem:GierigesGeldwechseln
Problem: Gebe Wechselgeld für den Betrag A mit möglichst wenig Scheinen
+Münzen aus.
Scheine und Münzen haben die in denom absteigend sortiert gespeicherten
Beträge.
Input Parameters: denom,A
greedy_coin_change(denom,A) {
i = 1
while (A > 0) {
c = A/denom[i] // ganzzahlige Division
print(“use ”+c+“ coins of denomination ”+denom[i])
A = A - c * denom[i]
i = i + 1
}
}
Op]mierungsproblem:GierigesGeldwechseln
Theorem: Greedy Coin Change (GCC) ist optimal für denom=(10,5,1), d.h.
GCC gibt eine minimale Anzahl von Münzen aus.
Beweis: vollständige Induktion über A.
Induktionsanfang: für A<5 können nur 1-er ausgeben werden.
Induktionsschritt:
1. Fall: 5≤A<10. Dann muss jede optimale Lösung einen 5-er beinhalten;
ansonsten könnten 5 1-er durch einen 5-er ersetzt werden und die Lösung
wäre nicht optimal. Die von GCC ausgegebene Lösung für A‘:=A-5 ist nach
Induktionsanfang optimal, damit auch die Lösung für A.
2. Fall: 10≤A. Dann muss jede optimale Lösung einen 10-er beinhalten;
sonst könnten 2 5-er (oder 1 5-er und 5 1-er oder 10 1-er) durch einen
10-er ersetzt werden und die Lösung wäre nicht optimal. Die von GCC
ausgegebene Lösung für A‘:=A-10 ist nach Induktionsvoraussetzung
optimal, damit auch die Lösung für A. qed
Op]mierungsproblem:GierigesGeldwechseln
Greedy Coin Changing ist auch optimal für EUR und $ (Bw. analog).
Greedy Coin Change ist nicht optimal für denom=(10,7,5,1).
(Nachweis durch Test für A=14).
Eine Verbesserung durch dynamische Programmierung ist für jede
Stückelung der Scheine und Münzen denom optimal.
MinimumSpanningTree(MST)Problem
Problem:
GegebenseieinzusammenhängendergewichteterGraphG(d.h.jede
KantehateinGewichtausdenreellenZahlen>0).
FindeeinenzusammenhängendenTeilgraphen,deralleKnotenvonG
enthält,undfürdendieSummederKantengewichteminimalist.
Bemerkung:DieserTeilgraphisteinBaum.
A
3
D
4
5
7
3
B
5
6
E
4
3
7
H
C
6
F
6
5
4
5
I
5
G
4
J
GierigerAlgorithmuszurMST-Suche,Version1
A1
1.  BeginneaneinembeliebigenKnoten.
2.  WählediekürzesteVerbindungzueinemunbesuchtenNachbarn.
3.  Fahremit(2.)fortbisalleKnotenbesuchtsind.
LiefertA1eineop]maleLösung(einenMST)?
Warumnicht?
Weilwirlokalop]maleEntscheidungen
4
5
A
B
C
treffen.
3
D
5
7
3
6
E
4
3
7
H
6
F
6
5
4
5
I
5
G
4
J
GierigerAlgorithmuszurMST-Suche,Version2:
KruskalsAlgorithmus
KruskalsAlgorithmus
1.  WähleeineKantemitminimalemGewicht,diekeinenZykluserzeugt.
2.  Fahremit(1.)fortbisalleKnotenbesuchtsindundwireinen
zusammenhängendenTeilgraphenerhalten.
LiefertKruskalsAlgorithmuseineop]maleLösung(einenMST)?
Warum?
4
5
A
B
C
Weilwirglobalop]maleEntscheidungen 3
6
4
5
6
treffen.
D
7
3
E
3
7
H
F
6
5
4
5
I
5
G
4
J
Implemen]erungvonKruskalsAlgorithmus
ZubeachtendePunkte:
•  BezeichnungderKnotenmitihremIndex1…n
•  Repräsenta]ondesGraphensalseineListevonKantenmitGewichten.
Bsp.:(1,2,1),(1,4,3),…
•  WirwählenjeweilsKantenmitminimalemGewicht;dazusor]erenwirdie
Kantenzunächst.
•  EineKantezwischenKnoteni,jerzeugteinenZyklus
⇔ i,jsindbereitsverbunden
⇔ i,jgehörenzurgleichenZusammenhangskomponente(“Komponente”)
Funk]onenfürüberschneidungsfreieMengen(Disjointsets):
•  Makeset(i)
ErzeugeeineMengemitdemeinzigenElementi
•  findset(i)
FindedieMenge,dieienthält
•  union(i,j)
VereinigedieMengenmitdenElementeniundj
A
3
D
3
3
7
5
B
4
E
7
H
KruskalsAlgorithmus
Eingabe: edgelist (die Liste der Kanten mit Komponenten v, w, g) und n.
Die Ausgabe gibt die Kanten in einem MST.
sort sortiert edgelist nach austeigendem Gewicht g.
kruskal(edgelist,n) {
sort(edgelist)
// edgelist[1] ist jetzt die kürzeste Kante
for i = 1 to n
makeset(i)
// jeder Knoten eine eigene Komponente
count = 0
// Anzahl Knoten im MST bisher
i = 1
// die erste zu untersuchende Kante
while (count < n - 1) {
if (findset(edgelist[i].v) != findset(edgelist[i].w)) {
println(edgelist[i].v + “ ” + edgelist[i].w)
count = count + 1
union(edgelist[i].v,edgelist[i].w) //merge components
}
i = i + 1
}
}
KorrektheitvonKruskalsAlgorithmus
Theorem:
SeiGeinverbundenergewichteterGraph.SeiG’einSubgrapheinesMSTT
vonG.SeiCeineZusammenhangskomponentevonG’.SeiSdieMengealler
KantenmiteinemKnoteninCunddemanderenKnotennichtinC.
WennwireineKantemitminimalemGewichtausSzuG’hinzufügen,dannist
derresul]erendeSubgraphebenfallsineinemMSTT’enthalten.
Korrolar
HierausfolgtdieKorrektheit(Op]malität)vonKruskalsAlgorithmus.
Bw.(Korrolar):pervollständigeInduk]on.
WirverfolgenKruskalsAlg.undzeigenmitHilfedesTheoremsjeweils,dasswir
immernochineinemMSTenthaltensind.SobaldalleKnoteninCliegen
habenwirdenvollständigenMST.qed
KorrektheitvonKruskalsAlgorithmus
Beweis(Theorem):Sei(v,w)eineKantemitminimalemGewicht,mitvinCund
wnichtinC,undCenthalteninG’.SeiTderMST,derG’enthält.
Falls(v,w)inTenthaltenist,sindwirfer]g.
Annahme:(v,w)istnichtinTenthalten.Füge(v,w)zuThinzu.Dieserzeugt
einenZyklusS.Seiw’derersteKnoteninSaufdemalterna]venWegvonv
nachw,dernichtinCliegt.Seiv’dervorhergehendeKnoten.EnŽernedie
Kante(v’,w’);diesergibtdenneuenSpanningTreeT’.
(v,w)isteineKantemitminimalemGewichtmiteinemKoteninCunddem
anderennichtinC.Dahergilt
weight(v’,w’)≥weight(v,w)
=> weight(T’)≤weight(T)
DaTeinMSTist,mussauchT’einMSTsein.qed
Vorlesungvom24.Januar
ParentPointer-Implemen]erungvonMengen
Alle Elemente sind in einer Liste gespeichert. Wir ordnen jedem Element
(Knoten) einen Index zu. Wir können direkt vom Index auf den Index des
Vaters zugreifen.
Eine Liste von 1-knotigen Bäumen (1-elementigen Mengen):
Index
1 2 3
4 5 6 7 8 9 10
Parent 1 2 3
4 5 6 7 8 9 10
Knoten A B C
D E F G H I
Index
1 2 3
4 5 6 7 8 9 10
Parent 6 1 1
6 4 6 6 3 6 10
Knoten A B C
D E F G H I
Eine Liste mit 2 Bäumen (2 Mengen)
J
J
Makeset&Findset,Version1
This algorithm represents the set {i} as a one-node tree.
Input Parameter: i
makeset1(i) {
parent[i] = i
}
This algorithm returns the root of the tree to which i belongs.
Input Parameter: i
findset1(i) {
while (i != parent[i])
i = parent[i]
return i
}
Mergetrees&Union,Version1
This algorithm receives as input the roots of two distinct trees and
combines them by making one root a child of the other root.
Input Parameters: i,j
mergetrees1(i,j) {
parent[i] = j
}
This algorithm receives as input two arbitrary values i and j and constructs
the tree that represents the union of the sets to which i and j belong. The
algorithm assumes that i and j belong to different sets.
Input Parameters: i,j
union1(i,j) {
mergetrees1(findset1(i), findset1(j))
}
Makeset&Findset,Version2:height
This algorithm represents the set {i} as a one-node tree and initializes its
height to 0.
Input Parameter: i
makeset2(i) {
parent[i] = i
height[i] = 0
}
This algorithm returns the root of the tree to which i belongs.
Input Parameter: i
findset2(i) {
while (i != parent[i])
i = parent[i]
return i
}
Mergetrees&Union,Version2:height
This algorithm combines trees by making the root of the tree of smaller
height a child of the other root.
Input Parameters: i,j
mergetrees2(i,j) {
if (height[i] < height[j])
parent[i] = j
else if (height[i] > height[j])
parent[j] = i
else {
parent[i] = j
height[j] = height[j] + 1
}
}
This algorithm constructs the union of the sets to which i and j belong. The
algorithm assumes that i and j belong to different sets.
Input Parameters: i,j
union2(i,j) {
mergetrees2(findset2(i), findset2(j))
}
LaufzeitderMengenopera]onen
Theorem:DieHöhederdurchdie“Version2”-Mengenopera]onen
entstehendenBäumefürMengenmitkElementenisthöchstenslogk.
Beweis:durchvollständigeInduk]on.
Induk]onsanfang:EinBaummit1Element(1Knoten)hatHöhe0=log(1).
Induk]onsschriH:Seik>1unddieBehauptungfürallep<kbereitsgezeigt.
SeiTeindurchdieMengenopera]onenerzeugterBaummitkKnoten.Wegen
k>1istTdurchdieVereinigungvonzweiTeilbäumenentstanden(T1mitHöhe
h1undk1<kKnoten,sowieT2mitHöheh2undk2<kKnoten).
NachInduk]onsvoraussetzungisth1≤logk1undh2≤logk2.
Fall1:h1≠h2.Danngilth=max{h1,h2}≤max{logk1,logk2}<log(k).
Fall2:h1=h2.SeiohneBeschränkungderAllgemeinheit(oBdA)k1≥k2.
Wegenk=k1+k2folgtk2≤½k.
h=1+h2≤1+logk2≤1+log(½k)=logk.qed
69
KruskalsAlgorithmus:Laufzeit
kruskal(edgelist,n) {
sort(edgelist)
// edgelist[1] ist jetzt die kürzeste Kante
for i = 1 to n
makeset(i)
// jeder Knoten eine eigene Komponente
count = 0
// Anzahl Knoten im MST bisher
i = 1
// die erste zu untersuchende Kante
while (count < n - 1) {
if (findset(edgelist[i].v) != findset(edgelist[i].w)) {
println(edgelist[i].v + “ ” + edgelist[i].w)
count = count + 1
union(edgelist[i].v,edgelist[i].w) //merge components
}
i = i + 1
}
}
FürnKnoten&mKanten(mitn<m):
•  Θ(mlogm)fürsort(edgelist)
•  makesetwirdn-maldurchlaufen,jeweilsO(1)
•  DieSchleifewirdmaximalmmaldurchlaufen;
alleMengenopera]onensindausO(logn)
DieGesamtlaufzeitistdaherausO(mlogm).
PrimsAlgorithmus
•  FindetebenfallsMSTineinemverbundenen,gewichtetenGraphen.
•  TeillösungensindbereitsBäume(andersalsbeiKruskalsAlgorithmus!).
Algorithmus:
1.  BeginnemiteinemStartknoten(1-kno]gerBaum).
2.  FügeeineKantemitminimimalemGewichthinzu,dieeineninzidenten
Knotenimgegenwär]genBaumundeinenKnotenausserhalbhat.
3.  Fahremit(2.)fort,bisalleKnotenverbundensind(alson-1mal).
Implemen]erung:
•  BuchführungüberKandidaten-Kantenwirdeinfacher,wennwirproKnoten
ausserhalbdesBaumsnureineminimaleKantezumBaumauflisten.
•  ArrayhmitKnotenvausserhalbdesBaumsunddemGewichteiner
minimalenKante(v,w)vonvzumBaum.
•  ArrayparentmitdenzugehörigenKanten:parent[v]=w.
•  hundparentmüsseninjederItera]onangepasstwerden.Hierzumüssenalle
KantenvomzuletztzumBaumhinzugefügtenKnotenvbetrachtetwerden.
PrimsAlgorithmus
histabstrakterDatentyp(ADT)mitOpera]onen:
•  h.init(key,n)-ini]alisierthmitdenWertendesArrayskey[1…n]
•  h.del()-enŽerntdenEintragmitminimalemGewichtinhundgibtden
entsprechendenKnotenaus(–>HinzufügenvonKnotenzumMST).
•  h.isin(w)-gibtTRUEfallswinh,sonstFALSE
(–>welcheKnotensindnochnichtimMST).
•  h.keyval(w)-gibtdaszuwgespeicherteGewichtzurück.
•  h.decrease(w,wgt)-ändertdasGewichtzuwaufwgt(–>wenneinneu
hinzugefügterKnotenzueinerverbessertenErreichbarkeitvonwführt).
EffizienteImplemen]erungz.B.
mitHilfeeinesbinärenMin-Heaps
undeinemHashfürisinundkeyval:
Opera'on Worst-case
'me
Init
Θ(n)
del
Θ(logn)
isin
Θ(1)
keyval
Θ(1)
decrease
Θ(logn)
PrimsAlgorithmus
Dieser Algorithmus findet einen MST in einem zusammenhängenden
gewichteten Graphen mit n Knoten.
Der Graph wird durch Adjazenzlisten repräsentiert. adj[i] verweist auf
den ersten Eintrag in einer verketteten Liste von Knoten, die alle Knoten
enthält, die über eine Kante direkt mit Knoten i verbunden sind.
Jeder Eintrag hat folgende Bestandteile:
•  ver, den mit i inzidenten Knoten;
•  weight, das Gewicht der Kante (i,ver);
•  next, ein Pointer auf den nächsten Knoten in der verketteten Liste
(oder null für den letzten Eintrag).
Der Startknoten ist start. Im MST gilt: der Vater von Knoten i ≠ start ist
parent[i], und parent[start] = 0.
∞ bezeichnet die größte darstellbare ganze Zahl.
Input Parameters: adj,start
Output Parameters: parent
prim(adj,start,parent) {
n = adj.last
// index of last entry = number of nodes
for i = 1 to n
key[i] = ∞
// key is a local array
key[start] = 0
parent[start] = 0
h.init(key,n)
// initialize h to the values in key
for i = 1 to n {
v = h.del() // delete & return smallest weight
ref = adj[v] // nodes linked to v
while (ref != null) {
w = ref.ver
if (h.isin(w) AND (ref.weight < h.keyval(w))) {
parent[w] = v
// update h and parent
h.decrease(w,ref.weight)
}
Laufzeit(nKnoten&mKanten):
ref = ref.next
Θ(nlogn)fürdel
}
Θ(m)fürwhileloop
}
O(mlogn)fürdecrease
}
=>O(mlogn)insgesamt
KorrektheitvonPrim’sAlgorithmus
Theorem:Prim’sAlgorithmusistkorrekt,d.h.erfindeteinenMST.
Beweis:durchVollständigeInduk]on.Wirzeigen,dassinjederItera]onvon
Prim’sAlgorithumsdergegenwär]geBaumTineinemMSTenthaltenist.
Induk]onsanfang:TrivialfürTmitnurdemStartknoten(ohneKanten).
Induk]onsschriH:
Induk]onsvoraussetzung:SeiG’derbisherigeBaumT’,erweitertumalle
KnotennichtinT’.
DannistT’eineKomponentevonG’,undT’istineinemMSTenthalten.
DienächstevonPrimsAlg.gewählteKante(v,w),dieT’zuTerweitert,erfüllt
danndieVoraussetzungendesfürdenBeweisderKorrektheitvonKruskal’s
AlgorithmusbewiesenenTheorems.Darausfolgtsofort,dassauchTin
einemMSTenthaltenist.
AmEndevonPrim’sAlgorithmussindalleKnoteninTenthalten,damitistTein
MST.qed
Dijkstra’sAlgorithmus
Dieser Algorithmus findet die kürzesten Wege von einem ausgewählten
Knoten zu allen anderen Knoten in einem zusammenhängenden,
gewichteten Graph mit n Knoten.
Auf einem kürzesten Weg ist der Vorgänger von Knoten i predecessor[i], mit
predecessor[start]=0.
Wie bei Prim‘s Algorithmus:
•  Der Graph wird durch Adjazenz-Listen repräsentiert.
•  Der Wert ∞ ist die größte verfügbare ganze Zahl.
•  Der abstrakte Datentyp h verfügt über die selben Operationen.
Input Parameters: adj,start
Output Parameters: parent
dijkstra(adj,start,parent) {
n = adj.last
// number of vertices
for i = 1 to n
key[i] = ∞
// key is a local array
key[start] = 0
predecessor[start] = 0
h.init(key,n) // initialize the container h to key values
for i = 1 to n {
v = h.del() // delete & return smallest weight
min_cost = h.keyval(v)
// associated weight
ref = adj[v] // list of nodes adjacent to v
while (ref != null) { // update predecessor & h
w = ref.ver // the linked node
if (h.isin(w) AND
(min_cost + ref.weight < h.keyval(w))) {
predecessor[w] = v
h.decrease(w, min_cost + ref.weight)
} // end if
ref = ref.next
} // end while
Laufzeit(nKnoten&mKanten):
} // end for
O(mlogn)insgesamt
}
(wiePrimsAlg.)
KorrektheitvonDijkstrasAlgorithmus
Theorem:DijkstrasAlgorithmusistkorrekt,d.h.erfindetdenkürzestenPfad
voneinemKnotenzuallenanderenKnoten.
BeweisperVollständigeInduk]on:injederItera]on,indervaushenŽernt
wird,istkey(v)dieLängeeineskürzestenPfadesvonstartzuv.
Induk]onsanfang:trivial,daderersteKnotenstartist.
Induk]onsschriH:vwurdegeradeenŽernt;fürallevorherenŽerntenKnoteni
giltkey(i)istLängeeineskürzestenPfades(Induk]onsvoraussetzung).
Wirzeigenzunächst:gibteseinenkürzestenWegvonstartzueinemKnotenw
derLänge<key(v),dannwurdewvorvenŽernt.Annahme,diesgiltnicht
fürw.Dannseiw’derjenigeKnotenaufeinemkürzestenPfadPvonstartzu
w,deramnächstenanstartliegtundnochinhist(imZweifelw=w’).Dann
istseinVorgängerw’’nichtinh,undesgilt:
key(w)≤key(w’)+weight(w’’,w’)≤lengthofP<key(v).Dannwarvnicht
derKnoteninhmitdemkleinstenkey.
InsbesonderekanneskeinenkürzerenWegvonstartzuvgeben(sonstwärev
schonvorheraushenŽerntworden).qed
HuffmanCodes
File-Komprimierungdurchneue(non-ASCII)KodierungdesAlphabets.
Standard-Kodierung(àlaASCII):CZeichenbenö]genlog2CBits.
(7Bitsfür128Zeichen+1BitfürParity)
Praxis:Dateienhabenz.B.häufigvieleZiffern,aberwenige„x“und„y“
WählekürzereRepräsenta]onfürhäufigereZeichen!
(Bsp.)
SolangeeinCodefüreinZeichennichtPräfixeinesanderenist,kannderCode
verkürztwerden->Präfix-code(mitunterschiedlichenBit-ZahlenfürZeichen)
DiesentsprichteinemvollständigenKodierungsbaum(jederinnereKnotenhat
zweiSöhne).
HuffmanCodes
Huffman‘sAlgorithmus:
WirsindFörstermiteinemWaldvonBäumen,dersichentwickelt.JederBaum
hateinGewicht:=dieSummederHäufigkeitenseinerBläHer.
Start:
CBäumeausjeeinemBlaH.
Wiederhole(C-1mal):
Wähledie2BäumemitkleinstemGewicht(Tiessindegal)undverbinde
siezueinemneuenBaum(durchHinzufügeneinergemeinsamenWurzel).
(Bsp.)
Huffman’sAlgorithm
This algorithm constructs an optimal Huffman coding tree. The input is an
array a of n ≥ 2 nodes. Each node has an integer member character to
identify a particular character, another integer member key to identify that
character’s frequency, and left and right members.
After the Huffman coding tree is constructed, a left member of a node
references its left child, and a right member of a node references its right
child or, if the node is a terminal vertex, its left and right members are null.
The algorithm returns a reference to the root of the Huffman coding tree.
The operator, new, is used to obtain a new node.
h is an ADT with the following properties.
If a is an array, the expression
h.init(a)
initializes the container h to the data in a.
h.del()
deletes the node in h with the smallest key and returns the node.
h.insert(ref )
inserts the node referenced by ref into h.
Huffman’sAlgorithm
Input Parameters: a
Output Parameters: None
huffman(a) {
h.init(a)
for i = 1 to a.last - 1 { // from 1 to n-1
ref = new node
// new root for two smallest trees
ref.left = h.del() // smallest tree
ref.right = h.del() // 2nd smallest tree
ref.key = ref.left.key + ref.right.key // occurrence
h.insert(ref)
// insert new (joint) tree
}
return h.del()
}
Huffman’sAlgorithm:BeweisderKorrektheit
Theorem:Huffman‘sAlgorithmuslieferteineop]maleKodierungbezüglichder
Dateigröße.
Beweisidee:
1.  DerBaumistvollständig.
2.  DiebeidenseltenstenZeichena,bsind]efsteBläHereinesop]malen
Kodierungsbaums.(Fallsnicht,wärec]efstesBlaH,dannliefert
VertauscheneinenbesserenCode)
3.  ZeichenaufderselbenEbenekönnenvertauschtwerden;deshalbsinda
undbBrüder
4.  Induk]onüberdieAnzahlderHäufigkeiten(Buchstaben)n;wirzeigen
dassdieSummedermitdenHäufigkeitengewichtetenPfadlängenin
Huffman‘sBaumdiegleicheistwieineinemop]malenBaum.
Induk]onsanfangn=2:esgibtnureinenBaum.
Induk]onsschriH:betrachtedenBauma,b,c,...undgreifedabeiaufden
Bauma+b,c,...zurück.(q.e.d.)
BeschränkteOp]mierung
Beispiele:
–  Pakteversand
•  Eingabe:NPaketeundMAuslierungsorte
•  Ziel:MinimieredieAuslierungszeit
•  Beschränkung(Constraint):XLastwagen
–  CPUalloca]on
•  Eingabe:NJobsmiteinerPriorität
•  Ziel:MaximieredenDurchsatz(gewichtetmitPriorität)
•  Beschränkung:XProzessoren,YSpeicher,ZZeit
Con]nuousKnapsackProblem:Beispiel
–  Eingabe:NunabhängigeKapitelIhrerAbschlussarbeit
–  Ziel:maximieredenGehaltderArbeit(mancheKapitelsindnichtso
gehaltvoll)
–  Prüfungsordnung:höchstens60Seiten
–  LöscheKapitel(oderTeilevonKapiteln)umdieszuerreichen.
•  GierigerAnsatz1:
–  Wählejeweilsdasgehaltvollstenochnichtberücksich]gteKapitel
–  Wennesnichtpasst,nehmenurdieerstenkSeiten,diepassen.
Kapitel Seiten
Gehalt
1
12
5
2
15
5
3
20
4
4
60
8
5
14
3
–  IstdieLösungop]mal?
Con]nuousKnapsackProblem:GierigerAnsatz2
•  GierigerAnsatz2:
–  Wählejeweilsdasnochnichtberücksich]gteKapitelmitdemhöchsten
GehaltproSeite
–  Wennesnichtpasst,nehmenurdieerstenkSeiten,diepassen.
Kapitel Seiten
Gehalt
Gehalt/Seite
1
12
5
0.42
2
15
5
0.33
3
20
4
0.2
4
60
8
0.13
5
14
3
0.21
–  IstdieLösungop]mal?
Con]nuousKnapsackProblem:Rucksackpacken
Kon'nuierlichesKnapsack-Problem
•  Gegeben:nObjekteundeinenRucksack(Knapsack)derKapazitätC.
ObjektihatGewichtwiundentsprichtdemProfit(Wert)pi.
•  FindediejenigenWertexi,diedenmaximalenProfit
n
∑ xi pi
i=1
n
unterderBedingung ∑ xi wi ≤ C, 0 ≤ xi ≤ 1 liefern.
i=1
Knapsack-Problem
•  Dasnicht-kon]nuierlicheKnapsack-Problem(odereinfach
Knapsack-Problem)ergibtsichunterderzusätzlichenBedingung
xi ∈{0,1}
•  Fürdasnicht-kon]nuierlicheProblemgibteskeinenkorrektengierigen
Algorithmus!
GierigerAlgorithmusfürdaskon]nuierliche
KnapsackProblem
The input to the algorithm is the knapsack capacity C, and an array a of size
n, each of whose entries specifies
•  an id (e.g., the first item might have id 1, etc.),
•  a profit p,
•  and a weight w.
The output tells how much of each object to select to maximize the profit.
Objects not selected do not appear in the output.
The function sort sorts the array a in nonincreasing order of the ratio of
profit to weight.
Input Parameters: a,C
continuous_knapsack(a, C)
{
n = a.last
for i = 1 to n
ratio[i] = a[i].p/a[i].w // Wert pro kg
sort(a,ratio)
// sortiere a nach absteigender ratio
weight = 0
// Gesamtgewicht des Rucksacks
i = 1
while (i ≤ n && weight < C)
{ // noch Platz?
if (weight + a[i].w ≤ C) {
// a[i] passt komplett?
println(“select all of object ” + a[i].id)
weight = weight + a[i].w
}
else {
// a[i] passt nicht komplett
r = (C - weight)/a[i].w
println(“select ” + r + “ of object ” + a[i].id)
weight = C
}
i = i + 1
Laufzeit:
}
Θ(nlogn)fürsSor]eren
}
Θ(n)fürloops
KorrektheitvonconVnuous_knapsack()
Theorem:conVnuous_knapsack()istkorrekt,d.h.liefertmaximalenProfit.
Bw.:DasGesamtgewichtderObjekteist>C(sonsttrivial).SeiPdertotale
Profit.BetrachteeinebeliebigeLösungmitxi’undP’.WirzeigenP’≤P.
n
n
n
∑ xi 'wi ≤ C =∑ xi wi ⇒ 0 ≤ ∑ (xi − xi ')wi .
i=1
i=1
i=1
SeikderkleinsteIndexmitxk<1.
pi pk
pi
pk
⇒ ( xi − xi ' ) ≥ ( xi − xi ' )
Füri<k,xi=1,also: xi − xi ' ≥ 0 ∧ ≥
wi wk
wi
wk
p
p
p
p
Füri>k,xi=0,also: xi − xi ' ≤ 0 ∧ i ≤ k ⇒ ( xi − xi ') i ≥ ( xi − xi ') k
wi wk
wi
wk
n
n
p
Insgesamtalso: P − P ' = ∑ (xi − xi ')pi = ∑ (xi − xi ')wi i ≥ ... ≥ 0. qed
wi
i=1
i=1
Approxima]vesbin-packing(PackeninKisten)
LösungensindnurNäherungen,abererwiesenermaßengute!
Problem:
GegebenseienNAr]kelderGrößes1,...,sNmit0<si≤1.
WiefasstmandiesesoinKistenmitVolumen1zusammen,dassmandie
minimaleAnzahlanKistenerhält?
Bsp.:s=0.2,0.5,0.4,0.7,0.1,0.3,0.8(1-dimensional)
Op]maleLösung:{0.8,0.2},{0.3,0.7},{0.5,0.1,0.4}
Approxima]vesbin-packing(PackeninKisten)
Online-Algorithmen:VerarbeitungderEingabeelementweise:Zuordnungzu
einerKiste,keinenachträglichenKorrekturen.
Kannkeineop]maleLösunggaran]eren:
I1:MAr]kelderGröße½+e
I2:MAr]kelderGröße½-e
Op]mal:erstjedesElementausI1ineineKiste,dannI2dazu;beinurI1
schlecht.
Theorem:EsgibtEingabenfürdasOnlineBin-Packing,dieLösungenmit≥4/3
Merzwingen,wennMdieop]maleKistenzahlist.
Beweis:Annahme:esgibteinenbesserenAlgorithmus(*).
I1:MAr]kelinbKisten,op]malistM/2,nach(*)b/(M/2)<4/3,alsob/M<2/3.
I2dazu:AlleBinsnachbhabennur1Ar]kel(2ausI2passennicht),also
insgesamt≥2M-bKistenfür2MAr]kel(op]malM),
Nach(*)gilt(2M-b)/M<4/3,alsob/M>2-4/3=2/3.DasisteinWiderspruchzu
oben,(*)mussalsofalschsein.qed
Herunterladen