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 h1 2h1 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
© Copyright 2024