Geamortiseerde analyse en union find

advertisement
Amorized Analysis
en
Union-Find
Algoritmiek
Vandaag
• Amortized analysis
– Technieken voor tijdsanalyse van algoritmen
• Union-find datastructuur
– Datastructuur voor operaties op disjuncte
verzamelingen
– Verschillende oplossingen
– Analyse van uiteindelijke oplossing
– Toepassing
2
Algoritmiek
Tijdsanalyse van een algoritme
• Soms: analyse van controlestructuur
– Kijken naar geneste loops, etc.
• Hier: een data-structuur met operaties
– Ge-amortiseerde tijd: hoeveel tijd kost elke
operatie gemiddeld over alle operaties.
• Drie technieken:
– Aggregate method
– Accounting method
– Potential method
3
Algoritmiek
Probleemstelling
• Data-structuur
• Verzameling operaties op een data-structuur
• Wat is de gemiddelde tijd in het slechtste geval per
operatie?
– Worst case average time: amortized time
4
Algoritmiek
Aggregate method
• Bereken totale tijd T(n) over een serie van n
operaties op de data-structuur.
• Amortized time is T(n)/n.
• Voorbeelden:
– Stack met multipop
– Binare teller
– Dynamische array
5
Algoritmiek
Stack met multi-pop
• Stack met drie operaties:
– Push(S,x): zet x bovenop de stack
– Pop(S): haal bovenste element van stack en
lever dat op
– Multipop(S,k): haal de bovenste k elementen
van de stack, of maak stack leeg als deze
minder dan k elementen heeft:
• Multipop(S,k)
while not(Stack-empty(S)) and k  0
do Pop(S); k = k – 1;
6
Algoritmiek
Aggregate analysis
voor de stack met multipop
• Worst-case tijd van multipop is O(n).
• Neem aan dat we beginnen met een lege stack.
• Amortized tijd van operaties is … O(1), want:
– Stel we doen n operaties op de stack.
– Dus doen we hooguit n keer een Push
– Dus kunnen we hooguit (minder dan) n keer een
element Pop-en
– Totale tijd over alle Pop- en Multipop-operaties: O(n)
– Totale tijd: O(n)
– Amortized time van operatie: O(n/n) = O(1)
7
Algoritmiek
Verhogen van een binaire teller
• Array A[0…k – 1] van
bits
• Initieel 000…00
• Increment(A)
i = 0;
While i < length(A) and
A[i] = 1
Do A[i] = 0; i ++
If i < length(A) then A[i]
=1
8
Algoritmiek
•
•
•
•
•
•
•
•
•
•
•
•
•
0
1
2
3
4
5
6
7
8
9
10
11
12
000000
000001
000010
000011
000100
000101
000110
000111
001000
001001
001010
001011
001100
0
1
3
4
7
8
10
11
15
16
18
19
20
Amortized analyse van binaire
teller
• Een enkele operatie kan O(k) tijd kosten.
• Amortized:
– Elke operatie zet slechts 1 bit van 0 naar 1,
maar misschien meerdere bits van 1 naar 0.
– Als we n Increment-operaties doen:
• Maximaal n keer bit van 0 naar 1.
• Dus ook maximaal n keer bit van 1 naar 0.
• Totaal O(n) werk
– O(1) amortized tijd van increment.
9
Algoritmiek
Dynamische array
• Array:
– Start op formaat 10
– Toevoegen van element kan totdat array vol is
(meestal O(1) werk, tenzij array vol)
– Als array vol:
• formaat = formaat * 2
• Maak nieuwe array met grootte formaat
• Kopieer oude array naar nieuwe array
• Kost O(formaat) tijd
10
Algoritmiek
Aggregate voor dynamische array
• Als we n inserts doen, dan:
– O(n) voor gewone inserts:
– Stel laatste verdubbeling gebeurde bij formaat k
– Totale tijd van verdubbelingen:
• O(10+20+40+ … + k ) = O(k)
• n <= 2k
• Dus O(n) totaal, dus O(1) amortized
11
Algoritmiek
De accounting method
• Iedere operatie betaalt hypothetische kosten.
• Daarmee:
– Betaalt hij voor de acties die hij doet
– Kan hij credit op objecten in de datastructuur
plaatsen
– Kan hij eventueel betalen met credit dat uit de
datastructuur gehaald wordt
12
Algoritmiek
Accounting method
Stack met multipop
• Operaties kosten:
– Push: 1
– Pop: 1
– Multipop: min(k, |S|)
• Geef geamortiseerde kosten:
– Push: 2. Zet 1 credit op element in S.
– Pop: 0. Betaal actie met credit.
– Multipop: 0. Betaal actie met credit
– Invariant: elk element in S heeft 1 credit.
13
Algoritmiek
Binaire teller met accounting
• Array A[0…k – 1] van
bits
• Initieel 000…00
• Increment(A)
i = 0;
While i < length(A) and
A[i] = 1
Do A[i] = 0; i ++
If i < length(A) then A[i]
=1
14
• Laat elke increment 2
kosten.
• Zet 1 credit op de 1 die we
gemaakt hebben.
• Betaal zetten van 1 naar 0
met credits op de 1-en.
• O(1) amortized.
Algoritmiek
Dynamische array met
accounting
• Als we een element toevoegen, dan:
– Geef 1 credit aan een element dat nog geen
credit heeft
– Geef 1 credit aan element zelf
• Als we verdubbelen, dan heeft elk element precies
1 credit
• Dus O(1) amortized
15
Algoritmiek
Potentiaal methode
• Potentiaal-functie
F: Datastructuur  reals
• Als D0 initiele datastructuur en Dj datastructuur na
j operaties, dan F(Dj)F (D0)
• Geamortiseerde kosten van een operatie i kunnen
we nemen als:
– Echte kosten ci plus F(Dj) – F(Dj –1)
– Merk op: totale kosten is minstens som van
geamortiseerde kosten.
16
Algoritmiek
Potentiaal methode voor
multipop
• Potentiaal van stack is aantal elementen op stack.
• Initieel 0; dus altijd minstens potentiaal van
initiele datastructuur.
• Geamortiseerde kosten Push: 2. (1 voor operatie
en 1 voor toename potentiaal).
• Geamortiseerde kosten Pop: 0. (1 voor operatie en
–1 wegens potentiaalverschil.)
• Geamortiseerde kosten Multipop: 0 (min(k,|S|)
voor operatie en – min(k,|S|) wegens
potentiaalverschil.)
17
Algoritmiek
Potentiaalmethode voor
binaire teller
• Potentiaal van bitstring: aantal bits dat 1 is.
• Initieel 0; dus altijd minstens potentiaal van
initiele datastructuur.
• Geamortiseerde kosten van operatie zijn hooguit
2.
18
Algoritmiek
Potentiaalmethode voor
dynamische array
• Stel we hebben een array met formaat f waarin n
elementen zitten
• Geef deze potentiaal 2n-f
• Elke gewone invoeging doet potentiaal met 2
stijgen
• Verdubbeling: we doen dit als n=f, dus potentiaal
is 2n-n = n, en na afloop is potentiaal 0, dus we
betalen de operatie met het potentiaalverschil
19
Algoritmiek
Union-find datastructuur
• Probleemstelling: datastructuur voor disjuncte
verzamelingen met operaties
– Vereniging (Union)
– Zoeken (Find)
• Verschillende datastructuren voor dit probleem
• Analyse van de verschillende datastructuren
• Uiteindelijke oplossing: `union by rank’ en padcompressie
• Toepassingen
– O.a. implementatie voor algoritme voor
schedulingprobleem
20
Algoritmiek
Disjuncte verzamelingen
• Partitie van universum
U in aantal disjuncte
deelverzameling van U.
– Elk element van U zit
in precies een
verzameling in de
collectie
a
b
d
c
e
g
f
U
U = { {a,b,c} , {d,e,g}, {f} }
21
Algoritmiek
Een ADT voor disjuncte
verzamelingen I: Create
• Verschillende operaties
– Create
– Union
– Find
a
b
f
U
22
a
d
c
Create ( v )
Voegt nieuwe verzameling aan
de collectie toe met element v
Wordt aangeroepen als v niet al
in de collectie zit.
e
b
d
c
g
f
U’
v
Algoritmiek
e
g
II:
Union
Vereniging
• Union (S1, S2)
– Wordt aangeroepen met
naam / objectverwijzing
/ identificatie van twee
verzamelingen
– Vervangt de
verzamelingen S1 en S2
in de collectie door een
verzameling S1 S2
23
Algoritmiek
a
S1 c
h
S2
b
d
g
e
f
a
v
b
d
c
h
v
f
e
g
III: Find
• Find (v)
• Levert de naam /
objectverwijzing /
identificatie op van de
verzameling waar v in
zit.
• Iedere verzameling heeft
dus unieke manier om
geïdentificeerd te worden
– Bijv. naam van een
uniek element uit de
verzameling
24
Algoritmiek
a
S1 c
h
S2
v
b
d
f
e
g
Find(a) geeft een
verwijzing naar S1.
Incrementeel samenhangende
componenten
• Graaf G.
• Operaties:
• Voeg een kant toe tussen
twee knopen x en y
• Geef de knopen in de
samenhangende
component van x
• Zitten x en y in dezelfde
samenhangende
component
25
Addedge(x,y)
S1 = Find(x)
S2 = Find(y)
if S1  S2
then Union(S1,S2)
Algoritmiek
Toepassing
Hoe implementeren we een
datastructuur voor `union-find’?
• Verschillende implementaties
• Soms willen/kunnen we de datastructuur met extra
operaties uitbreiden (zie werkcollege).
• Operaties moeten vlot gaan
26
Algoritmiek
Heel simpel idee: array
• Houdt bij elk element bij de naam van de verzameling
waar deze in zit: set(v)
• Find: O(1).
• Union (S, T):
– Vervelend:
• Of het hele array langsgaan en voor alle elementen
kijken of ze in S en T zitten
• Of we hebben voor verzamelingen S en T
opgeslagen welke elementen erin zitten:
– Maar dan hebben we de array niet zo nodig
• Create: lastig, want hoe lang moet de array worden?
27
Algoritmiek
Datastructuur met lijsten
• Een verzameling wordt gerepresenteerd met een
lijst van zijn elementen; elk element heeft een
pointer naar zijn representatie (bijv.: 1e element).
28
a
b
c
d
a
b
c
d
Algoritmiek
e
e
f
f
g
g
Verbetering 1
• 1e lijst moet doorgelopen worden, alleen om
laatste element te vinden om pointer naar 1e
element van 2e lijst te maken
a
b
c
d
a
b
c
d
Houdt dus ook een pointer
naar29het laatste element bij
e
e
f
f
g
g
O(1) extra werk
aan deze pointer
Algoritmiek
Verbetering 2
• Als we pech hebben / dom zijn, wordt grote lijst
achter kleine lijst gezet
e
e
a
b
c
d
a
b
c
d
Dus …
30
Algoritmiek
Union by size
• Houdt van elke verzameling ook het formaat bij.
• Bij een vereniging:
– Zet de kleinste lijst achter de grootste
– Tel de formaten op.
• Hoeveel tijd kost dit?
– Hoeveelheid tijd is
• O(1) voor find
• O(1) voor create
• O(1+ lengte kortste rij) voor union: hoeveel is dat nu
precies?
31
Algoritmiek
Analyse union by size
• Stel element x zit in verzameling met formaat n1 en union
wordt gedaan met verzameling met formaat n2.
– Als n1 n2, dan moet de pointer naar het eerste element
worden omgezet, en zit x na afloop in een verzameling
met n1 + n2 2*n1 elementen.
– Anders wordt de pointer naar het eerste element niet
omgezet.
• Als |U|=n, dan kan een element maar hooguit log n keer in
een minstens twee keer zo grote verzameling komen.
• Dus: totale hoeveelheid werk van het omzetten van
pointers over alle union-operaties is O(n log n).
– O(log n) gemiddeld per union.
32
Algoritmiek
Tijdgrenzen lijsten
met union by size
• Find: O(1)
• Create: O(1)
• Union:
– O(n) worst case
– O(log n) geamortiseerd
33
Algoritmiek
Union-find met snelle union
• Duur was: omzetten van alle pointers naar het 1e
element.
• Dus, laten we dat dan niet doen.
34
a
b
c
d
a
b
c
d
e
Zoeken gaat in meerdere
stappen
Algoritmiek
e
f
f
g
g
Observaties
• Zoeken: ga een aantal pijlen naar voren af, tot je
aan begin van de lijst gekomen bent.
• De lijst hoeft geen lijst meer te zijn: we gebruiken
de lijst niet meer.
35
a
b
c
d
e
f
g
a
b
c
d
e
f
g
Algoritmiek
Boomstructuur
• Een verzameling wordt gerepresenteerd door een
boom.
• Pijlen wijzen omhoog, naar wortel. Identiteit van
verzameling is / wordt opgeslagen in wortel van
boom.
a
a b c d
e
f
g
c
36
e
b
Algoritmiek
d
f
g
Find in boomstructuur
Find (x)
r = x;
while parent(r)  r
do r = parent r
Return informatie opgeslagen bij r
a
e
b
c
37
Algoritmiek
d
f
g
Union in boomstructuur
• Hang kleinste boom onder grootste boom
• Update formaat
a
h
i
n
m
38
l
e
b
k
Algoritmiek
c
j
d
f
g
Analyse Union-Find met
boomstructuur
• Diepte van boom O(log n)
• Dus: Find kost O(log n) tijd.
• Union kost O(1) tijd, plus evt. tijd voor vinden van
wortels (m.b.v. 1 of 2 finds).
39
Algoritmiek
Diepte van boom bijhouden
• In plaats van aantal
knopen: houdt diepte van
boom bij.
• Noemen we rang.
• Als rang(S1) < rang(S2)
dan hang S1 onder S2
h
• Als rang(S2) < rang(S1)
n
dan hang S2 onder S1
• Als rang(S1) = rang(S2) m l
dan hang S2 onder S1 en
tel 1 op bij de rang van S1
40
Algoritmiek
a
e
b
c
i
k
j
d
f
g
Union by rank
• Rang = diepte van boom
• Als wortel rang r heeft, dan zijn er 2r knopen in
zijn verzameling
• O(log n) tijd voor find
• O(1) tijd voor Union
41
Algoritmiek
Padcompressie
• Observatie: meerdere Finds op hetzelfde element
herhalen veel werk.
• De boom is niet binair – hoeft ook niet!
• We kunnen elementen direct onder de wortel van
de boom hangen: scheelt de volgende keer veel
werk.
42
Algoritmiek
Padcompressie
d
d
c
a
b
a
43
Algoritmiek
b
c
Padcompressie - pseudocode
Findwithpathcompression(x)
r = x;
while parent(r)  r
do r = parent(r);
y = x;
Find met padcompressie
kost O( find zonder padcompressie ):
while y  r
We gaan 2 keer het pad af
do z = parent(y);
parent(y) = r;
y = z;
return(r);
44
Algoritmiek
Snelle en langzame functies
• Ackermann; k  0; j  1:
– A0(j) = j+1 j+1 keer
– Ak(j) = Ak-1Ak-1…Ak-1(j) als k>0.
• Inverse Ackermann
– a(n) = min{ k>0 | Ak(1) > n}
• Log-ster
i keer
– log*(n) = min {i | log log … log (n) < 1}
• Inverse Ackermann in praktijk nooit meer dan 4;
log-ster in praktijk nooit meer dan 5.
45
Algoritmiek
Union-find met union by rank
en padcompressie
• Stelling. Als we n creates en m finds doen, dan
kosten de finds samen Q(m a(m,n)) tijd.
• We gaan bewijzen:
• Stelling. Als we n creates en m finds doen, dan
kosten de finds samen O(n+m log* n) tijd.
46
Algoritmiek
Observaties over rangen
• Op ieder pad omhoog in de boom stijgen de rangen.
• De rang van een knoop is initieel 0, kan alleen maar stijgen
gedurende de loop van het algoritme, en blijft gelijk nadat
de knoop geen wortel meer is.
• De waarde van de rang(parent(x)) daalt nooit.
• Als x wortel van een boom is, dan is het formaat van de
verzameling van x minstens 2rang(x).
• Er zijn hooguit n / 2r knopen met rang r.
• Iedere knoop heeft rang hooguit log n.
47
Algoritmiek
Verdeel de rangen in blokken
• Rang r zit in blok log* r.
• Schrijf B(-1)=-1; B(0)=0; B(1) = 1.
• B(j) =
2
2
2
j keer, j>1
• Blok j is {B(j – 1)+1, … , B(j)}.
48
Algoritmiek
B(j) = 2B(j-1)
Kosten van find
Indelen in categorieën
• 1 eenheid kosten per knoop op wortelpad.
– Wortel: O(1) per find
– Kind van wortel: O(1) per find
– Blokkosten: Voor ieder blok: bovenste knoop
op wortelpad met rank in blok.
– Springkosten: Knopen met een rang anders dan
de rang van de wortel, en niet bovenste knoop
in blok
– Padkosten: Alle andere knopen
49
Algoritmiek
Blokkosten en springkosten
• Er zijn O(log* n) blokken. Iedere find heeft hooguit 1
knoop per blok die blokkosten krijgt:
– O(log* n) per find blokkosten.
• Springkosten:
– Nadat een knoop springkosten gekregen heeft, zal het
daarna alleen nog maar wortel, kind van wortel, of
blokkosten krijgen:
• Nooit meer springkosten en padkosten
• Want bovenste knoop in blok op elk wortelpad.
• Dus totaal O(1) per knoop = O(n) totaal over alle
finds
50
Algoritmiek
Padkosten
• Als knoop padkosten krijgt, dan
– Zit zijn ouder met rang in zelfde blok.
– Krijgt hij een nieuwe ouder met een kleinere rang.
• Knoop in blok j kan B(j) – B(j – 1) – 2 keer padkosten
krijgen: daarna zit zijn ouder zeker in een ander blok.
(Blok j heeft B(j) – B(j – 1) elementen.)
• Totale padkosten: som over alle blokken van aantal knopen
met rang in dat blok * (B(j) – B(j – 1) –2).
• Aantal knopen met rang in blok j: schrijf dit als N(j)
51
Algoritmiek
N(j)  3n/2B(j)
Gebruik dat er hooguit n/2r knopen met rang r zijn
N(0)  n / 20 + n / 21 = 3n / 2B(0)
Als j>0:
B( j )
n
N ( j)  

r
r  B ( j 1) 1 2
n
2 B ( j 1)1
52
B ( j ) ( B ( j 1) 1)

r 0

1
n
1
n
n
 B ( j 1)1  r  B ( j 1) 
r
2
2
2
B( j )
r 0 2
Algoritmiek
Tellen van padkosten

log*n 1
j 0
N ( j ) * B( j )  B( j  1)  2   j 0
log*n 1
3
n log* n
2
53
Algoritmiek
3n
B( j ) 
2 B( j )
Totaal
•
•
•
•
•
54
Wortel: O(m)
Kind van wortel: O(m)
Blokkosten: O(m log* n) totaal
Springkosten: O(n)
Padkosten: O(m log* n)
Algoritmiek
Union find met padcompressie en
union by rank
• Een enkele find kan veel tijd (O(log n)) kosten.
• Maar alle finds bij elkaar nauwelijks meer dan
lineaire tijd!
• Nuttig principe:
– Extra werk maar niet veel om later tijd te
besparen.
55
Algoritmiek
Toepassing voor
schedulingprobleem
• n taken
– Iedere taak kost evenveel (1) tijd
– Taken hebben een deadline di
– Taken hebben een opbrengst gi
– Een taak brengt gi op dan en slechts dan als de taak
uitgevoerd is op tijd di of eerder
• Welke taken voeren we uit, en in welke volgorde, zodat
– Taken uitgevoerd uiterlijk op deadline
– Totale opbrengst zo groot mogelijk
• Stel we hebben taken al gesorteerd op dalende opbrengst.
56
Algoritmiek
Disjuncte verzamelingen
• Neem een verzameling bestaande uit
– Tijdstip dat nog niet gebruikt is
– Alle latere gebruikte tijdstippen voor het
volgende nog niet gebruikte tijdstip.
• Bijhouden met union-find datastructuur; voor elke
verzameling houden we het vrije tijdstip bij.
57
Algoritmiek
Implementatie van `rechtsaanschuif’ algoritme
• Zoeken van leeg tijdstip: find operatie
• Plannen van taak op tijdstip t:
– Union van verzameling die t bevat en de
verzameling die t – 1 bevat.
• Totale tijd:
– O(n a(2n,n)) : bijna linear!
58
Algoritmiek
Conclusie
• Drie methoden voor analyse van geamortiseerde
tijd van data structuur
• Union-find datastructuur
• Toepassing van UF komt ook bij algoritme voor
minimum opspannende bomen
59
Algoritmiek
Download