Föreläsning 6

Föreläsning 6
Prioritetsköer och heapar.
Union/Find
TDDI16: DALG
Utskriftsversion av föreläsning i Datastrukturer och algoritmer 28 september 2015
Tommy Färnqvist, IDA, Linköpings universitet
6.1
Innehåll
Innehåll
1
Prioritetsköer
1
2
Heapar
2
3
Union/Find
7
1
6.2
Prioritetsköer
Prioritetsköer
En vanligt förekommande situation:
• Väntelista (jobbhantering på fleranvändardatorer, simulering av händelser)
• Om en resurs blir ledig, välj ett element från väntelistan
• Valet är baserat på någon partial/linjär ordning:
– jobbet med högst prioritet ska köras först,
– varje händelse ska inträffa vid en viss tidpunkt; händelserna ska bearbetas i tidsordning
6.3
ADT prioritetskö
•
•
•
•
Linjärt ordnad mängd K av nycklar
Vi lagrar par (k, v) (som i ADT Dictionary), flera par med samma nyckel är tillåtet
en vanlig operation är att hämta par med minimal nyckel
Operationer på en prioritetskö P:
– makeEmptyPQ()
– isEmpty()
– size()
– min(): hitta ett par (k, v) som har minimalt k i P; returnera (k, v)
– insert(k, v): sätt in (k, v) i P
– removeMin(): ta bort och returnera ett par (k, v) i P med minimalt k; error om P är tom
6.4
Implementation av prioritetsköer
• Vi kan t.ex. använda (sorterade) länkade listor, BST eller hashtabeller
• En annan idé: använd ett fullständigt binärt träd där roten i varje (del)träd T innehåller det minsta
elementet i T
1
Det här är ett partiellt ordnat träd, också kallat heap!
2
6.5
Heapar
Höjden av en heap
Proposition 1. En heap som lagrar n nycklar har höjd O(log n)
Bevis. Vi använder att en heap är ett fullständigt binärt träd.
• Låt h vara höjden av en heap som lagrar n nycklar
• Eftersom det finns 2i nycklar på djup i = 0, . . . h − 1 och minst en nyckel på djup h får vi n ≥ 1 + 2 +
4 + . . . + 2h−1 + 1
• Alltså är n ≥ 2h , d.v.s. h ≤ log2 n
djup nycklar
0
1
1
2
h­1
2h­1
h
1
6.6
Att uppdatera en heapstruktur
• Med sista lövet menar vi den sista noden i en traversering i levelorder
• removeMin(PQ) // ta bort roten
– Ersätt roten med sista lövet
– Återställ den partiella ordningen genom att byta noder nedåt ”down-heap bubbling”
• insert(PQ, k, v)
– Sätt in ny nod (k, v) efter sista lövet
– Återställ den partiella ordningen genom ”up-heap bubbling”
6.7
Insättning i en heap
• Metoden insert i ADT priokö svarar mot insättning av nyckel k i heapen
• Insättningsalgoritmen består av tre steg
– Hitta platsen för insättning z (det nya sista lövet)
– Lagra k vid z
– Återställ heapegenskapen
2
2
5
6
z
9
7
nytt sista löv
2
5
6
9
z
7
1
6.8
Upheap
• Efter insättning av en ny nyckel k är det inte säkert att heapegenskapen fortfarande är uppfylld
• Metoden upheap återställer heapegenskapen genom att byta k längs uppåtgående stig från insättningsnoden
• upheap terminerar när nyckel k når roten eller en nod vars förälder har en nyckel som inte är större
än k
• Eftersom en heap har höjd O(log n) går upheap i tid O(log n)
2
1
5
1
9
z
7
5
6
9
2
7
z
6
6.9
Borttagning från en heap
• Metoden removeMin i ADT priokö svarar mot borttagning av rotnyckeln från heapen
• Borttagningsalgoritmen består av tre steg
– Ersätt rotnyckeln med nyckeln i det sista lövet w
– Ta bort w
– Återställ heapegenskapen
2
5
9
7
6
w
sista lövet
7
5
9
w
6
nytt sista löv
6.10
Downheap
• Efter ersättning av rotnyckeln med nyckel k från sista lövet är det inte säkert att heapegenskapen
fortfarande är uppfylld
3
• Metoden downheap återställer heapegenskapen genom att byta k längs nedåtgående stig från insättningsnoden
• downheap terminerar när nyckel k når ett löv eller en nod vars barn har nycklar som inte är mindre
än k
• Eftersom en heap har höjd O(log n) går downheap i tid O(log n)
7
5
9
w
5
6
7
9
w
6
6.11
Egenskaper
• size(), isEmpty(), min(): O(1)
• insert(), removeMin(): O(log n)
Kom ihåg arrayrepresentationen av BST Ett fullständigt binärt träd. . .
• Kompakt arrayrepresentation
• ”Bubble-up” och ”bubble-down” har snabba implementationer
6.12
Exempel: ”bubble-up” efter insert(4,15)
6.13
Slå ihop två heapar
• Givet två heapar och en nyckel k
• Skapa en ny heap där rotnoden lagrar nyckel k och med de två givna heaparna som delträd
• Kör downheap för att återställa heapegenskapen
4
3
2
8
5
4
6
7
3
2
8
5
4
6
2
3
4
8
5
7
6
6.14
Exempel: Konstruktion av heap botten-upp
10 7
16
15
8
25 5
4
25
16
11 27 16 15 4
12
6
5
15
4
12 6
7
7
23 20
23
11
12
6
20
27
7
23
20
6.15
Exempel: Konstruktion av heap botten-upp
25
16
5
15
4
15
16
11
12
6
4
25
5
27
9
23
6
12
11
Exempel: Konstruktion av heap botten-upp
5
20
20
9
23
27
6.16
7
8
15
16
4
25
5
6
12
11
20
9
4
5
25
27
6
15
16
23
7
8
12
11
20
9
23
27
6.17
Exempel: Konstruktion av heap botten-upp
10
4
6
15
16
5
25
7
8
12
11
20
9
23
27
4
5
6
15
16
7
25
10
8
12
11
20
9
23
27
6.18
Analys
• Vi visualiserar värstafallstiden för ett anrop till downheap med en stig som först går till höger och
sedan upprepade gånger går till vänster till botten av heapen
• Eftersom varje nod traverseras av som mest två sådana stigar är den totala stiglängden O(n)
• Alltså är tiden för att konstruera en heap botten-upp O(n)
• Den här konstruktionsmetoden är snabbare än n upprepade insättningar
6.19
Heapvarianter
Olika partialordningar
• minsta nyckeln i roten (minHeap)
• största nyckeln i roten (maxHeap)
Olika arrayrepresentationer
6
• numrering framåt i levelorder (med början från 0 eller 1)
• numrering bakåt i levelorder (med början från 0 eller 1)
6.20
3
Union/Find
Partitioneringar med Union/Find-operationer
• makeSet(x): Skapa en mängd enbart innehållande elementet x och returnera positionen som lagrar x
den nya mängden.
• union(A, B): Returnera mängden A ∪ B, förstör de gamla A och B.
• find(p): Returnera mängden som innehåller elementet i position p.
6.21
Exempel: Dynamisk konnektivitet
Fråga: finns det en stig mellan p och q?
•
•
•
•
•
•
•
Pixlar i ett digital foto
Datorer i ett nätverk
Vänner i ett socialt nätverk
Transistorer på ett datorchip
Element i en matematisk mängd
Variabelnamn i ett datorprogram
Metalliska delar av ett kompositsystem
6.22
Listbaserad implementation
• Varje mängd lagras som en sekvens representerad av en länkad lista
• Varje nod lagrar ett objekt innehållande ett element och en referens till mängdens namn
7
6.23
Analys av listbaserad representation
• När union utförs, flytta alltid element från den mindre mängden till den större mängden
– Varje gång ett element flyttas hamnar det i en mängd som är åtminstone dubbelt så stor som den
gamla mängden
– Alltså, ett element kan flyttas max O(log n) gånger
• Total tid för att utföra n union- och find-operationer är O(n log n)
6.24
Trädbaserad implementation
•
•
•
•
Varje element lagras i en nod som innehåller en pekare till ett mängdnamn
En nod v vars pekare pekar på nod v är också ett mängdnamn
Varje mängd är ett träd, rotat i en nod med själrefererande mängdnamnspekare
T.ex. mängderna ”1”, ”2” och ”5”:
8
1
4
2
7
3
5
6
9
8
10
11
12
6.25
Operationer
• För att utföra union, låt bara roten av ett träd peka på roten av det andra
• För att utföra find, följ mängdnamnspekarna från startnoden till en självrefererande nod träffas på!
9
5
2
8
3
10
6
11
9
12
5
2
8
3
10
6
11
9
12
6.26
En heuristik
• Union via storlek:
– När union utförs, låt roten i det mindre trädet peka på roten i det större
• Medför O(n log n) tid för att utföra n union- och find-operationer:
– Varje gång vi följer en pekare kommer vi till ett delträd som är åtminstone dubbelt så stort som
det förra delträdet
– Alltså kommer vi att som mest följa O(log n) pekare för någon find
5
2
8
3
10
6
11
9
12
6.27
En till heuristik
• Stigkomprimering:
– Efter att find utförts komprimera alla pekare på stigen som precis traverserats så att de alla pekar
på roten
5
8
5
10
8
11
3
11
12
2
6
10
12
2
3
9
6
9
• Medför O(n log∗ n) tid för att utföra n union- och find-operationer.
6.28
10