Datastrukturer föreläsning 9 Maps 1
Minsta uppspännande träd Maps 2
Minsta uppspännande träd Uppspännande träd till graf fritt delträd innehåller alla noderna Minsta uppspännande träd (MST) är det uppspännande träd som har minst totalvikt (summera bågarnas vikter) Tillämpningar Kommunikationsnätverk Transportnätverk DEN 4 DFW 1 8 9 ORD 6 STL 10 3 5 ATL PIT DCA 2 7 Maps 3
Kruskals algoritm för MST De snåla kommunalpolitikernas algoritm för att asfaltera vägar i kommunen! 1 ORD 10 PIT DEN 4 9 6 STL 3 7 DCA 8 5 2 DFW ATL Maps 4
Kruskals algoritm för MST De snåla kommunalpolitikernas algoritm för att asfaltera vägar i kommunen! 1. Asfaltera den kortaste vägen i kommunen 2. Asfaltera den näst kortaste vägen i kommunen, osv 3. Asfaltera dock aldrig någon väg mellan två noder som redan är förbundna med asfalterade vägar DEN 4 DFW 1 8 9 ORD STL 10 ATL PIT Maps 5 6 5 3 DCA 2 7
Prims algoritm för MST Kommunalpampens algoritm för att asfaltera vägar i kommunen DEN 4 1 8 9 ORD 6 STL 5 10 3 PIT DCA 2 7 DFW ATL Maps 6
Prims algoritm för MST Kommunalpampens algoritm för att asfaltera vägar i kommunen 1. Välj en startnod (kommunalpampens hus) t ex DCA 2. Asfaltera kortaste vägen från DCA. Den går till ATL. 3. Utvidga sedan successivt det sammanbundna asfaltsvägnätet med så korta vägar som möjligt som ger en förbindelse till en ny nod. DEN 4 DFW 1 8 9 ORD 6 STL 10 3 5 ATL PIT DCA 2 7 Maps 7
Prims algoritm för MST Kommunalpampens algoritm för att asfaltera vägar i kommunen 1. Kommunalpampen bor i DCA 2. Asfaltera DCA - ATL (kortaste vägen från DCA) 3. Asfaltera DCA STL (kortaste vägen till ny nod från DCA eller ATL) 4. Asfaltera STL ORD (kortaste vägen till ny nod från DCA, ATL eller STL). Etc. DEN 4 DFW 1 8 9 ORD STL 10 ATL PIT Maps 8 6 5 3 DCA 2 7
Prims algoritm Algoritmen liknar Dijkstras algoritm. Även här har vi en prioritetskö Q med obesökta noder. För varje nod u lagrar vi en båge e = E[u] med vikt w = D[u]. Vikten används som nodens prioritet. Vi bygger dessutom upp ett träd T med besökta noder och bågar som spänner upp dem. När algoritmen terminerar innehåller T ett minsta uppspännande träd. Maps 9
Prims algoritm Algorithm Prim(G,s) D[s] 0, D[u] infinity for all nodes u different from s. E[u] null for all nodes u T new free tree, initially empty Q new priority queue with triples (D[u],(u,E[u])), where weights D[u] are priorities. while Q.isEmpty() (u,e) Q.removeMin() ( visit u along e) add node u and (non-null) edge e to T for each node z adjacent to u such that z is in Q do if weight(u,z) < D[z] then D[z] weight(u,z) and E[z] the edge from u to z update the priority of z in Q return D[u] for each node u Maps 10
Summering, grafalgoritmer Djupet först och bredden först sökning: O(n+m) med grannlista Hitta ev. cykler, uppspännande träd, en väg mellan två givna noder. Upprepad DFS eller BFS på alla noder i grafen ger transitiva höljet O(n(n+m)) Bredden först sökning hittar dessutom kortaste vägen till en viss nod Maps 11
Summering: grafalgoritmer Floyd-Warshall: O(n 3 ) om areadjacent är O(1) Beräknar transitiva höljet av en riktad graf Topologisk sortering: riktade acykliska grafer O(n+m) med grannlista Sortera grafen. Exempel: graf med förkunskaper för kurser, i vilken ordning kan vi läsa kurserna? Maps 12
Summering: grafalgoritmer Dijkstras algoritm: viktad graf O((m+n) log n) med heap och grafen implementerad med grannlistor. O(m+n 2 ) med osorterad prioritetskö och grafen implementerad med grannlistor. Bättre för täta grafer med många bågar, varför? Hittar kortaste avståndet/vikten mellan två noder. Ett slags BFS-sökning för viktade grafer Maps 13
Summering: grafalgoritmer Kruskals och Prims algoritmer: O((m+n)log n) med heap och grannlistor (även här kan man använda osorterad prioritetskö, se diskussion om Dijkstra) Minsta uppspännande träd. Prims och Kruskals algoritmer liknar Dijkstras, men prioritetsköerna innehåller bågvikter i stället för längden på kortaste vägen till startnoden. Kruskal, Prim och Dijkstra är alla exempel på giriga ( greedy ) algoritmer. Se algoritmkursen om allmänna tekniker, t ex även söndra och härska ( divide and conquer ), m fl. Maps 14
Binära sökträd < 6 2 > = 1 4 8 9 Maps 15
Varför binära sökträd? Binärsökning i sorterat fält: - snabb uppslagning (O(log n)) men - långsam insättning och borttagning (O(n)) Binärt sökträd: - snabb uppslagning, insättning och borttagning om trädet är balanserat (O(log n)) Maps 16
Vad är ett binärt sökträd? Definition Binära träd som lagrar nycklar (och evt element) och har sökträdsegenskapen: Låt v vara trädets rot och u och w vara vänster resp höger barn. Då gäller key(u) < key(v) < key(w) Vänster och höger delträd är också binära sökträd. Alltså gäller att alla nycklar i vänster delträd är mindre än rotens nyckel, och alla i höger delträd är större än rotens nyckel. (Vi förutsätter här att vi lagrar avbildningar, dvs inga dublettnycklar.) Maps 17
Sökning Algorithm findelement(k, o) if o = null return NO_SUCH_KEY if k = key(o) return element(o) else if k < key(o) return findelement(k, o.left) else if k > key(o) return findelement(k, o.right) Maps 18
findelem i Haskell BinTree a = Empty Node a (BinTree a) (BinTree a) findelem :: Ord k => k -> BinTree (k,v) -> Maybe v findelem k Empty = Nothing findelem k (Node (k,v) left right) k == k = Just v k < k = findelem k left k > k = findelem k right Maps 19
Insättning Operationen insertitem(k,v) sätter in ett nytt par (k,v) på rätt plats Exempel: sätt in ett nytt par med nyckel 5 2 2 < > 1 4 8 1 4 8 5 6 > 6 9 9 Maps 20
Borttagning: fall 0 och 1 barn Operationen removeelement(k) söker efter nyckeln k och om den finner den tar bort motsvarande nod v Fall 0: om v saknar barn är vi klara. Fall 1: om v har precis ett barn flyttar vi upp delträdet, se fig: ta bort nyckeln 4 2 1 4 8 2 > < v 1 5 8 5 6 6 9 9 Maps 21
Borttagning: fall 2 barn 1 Om noden v som ska tas bort har två barn: Leta upp noden w som kommer efter v i inordning (dvs har närmast större nyckel i sökträdet). w måste vara ett löv. (Det går förstås också bra med närmast mindre nyckel.) Ersätt v med w! Exempel: ta bort 3! 1 2 2 3 w 5 v 5 8 6 9 w 8 6 9 Maps 22
Tidskomplexitet värsta fallet Antag att det binära sökträdet har n noder och höjden h Utrymmet är O(n) findelement, insertitem och removeelement är O(h) Höjden h är O(n) i värsta fall O(log n) i bästa fall bästa fallet Maps 23
AVL-träd 1 2 5 2 0 4 1 8 9 3 2 1 11 1 7 Maps 24
AVL-träd AVL-träd är balanserade BST: för alla noder gäller det att höjdskillnaden mellan vänster och höger delträd 0 är högst 1 Sökning fungerar som i vanliga binära sökträd. Insättning och borttagning fungerar också som vanligt, men obalans kan uppstå, så vi måste eventuellt balansera om trädet. 1 2 Maps 25 5 1 8 0 6 3 9 2 1 0 11
Insättning i AVL-träd obalans Sätt först in det nya elementet på samma sätt som i ett vanligt BST! Det nya trädet kan bli obalanserat Balansera om trädet! Exempel: vi har satt in en ny nod med nyckel 7: 0 1 2 Maps 26 5 1 8 1 ny nod 6 4 9 3 2 0 7 0 lokal obalans 11 lokal obalans
Enkelrotation: princip nederst lokal obalans alltför djup nod balansen återställ d Maps 27
Enkelrotation: exempel 5 obalans 9 3 9 5 11 8 11 10 alltför djup nod 3 8 10 Balansen återställ d Maps 28
Dubbelrotation: princip nederst lokal obalans alltför djup nod balansen återställ d Maps 29
Dubbelrotation: exempel 2 5 9 obalans 5 8 9 6 8 10 alltför djup nod 2 6 10 balansen återställ d Maps 30
Trenodsomstrukturering Enkel och dubbelrotationer kallas med ett gemensamt namn trenodsomstruktueringar. Vi letar upp tre noder: den nedersta noden med lokal obalans samt dess barn och barnbarn så att barnet och barnbarnet tillhör delträd som har blivit alltför djupa. Dessa tre noder bestämmer fyra delträd. Vid enkelrotation gör man barnet till ny förälder med den gamla föräldern och barnbarnet som nya barn. Vid dubbelrotation gör man barnbarnet till ny förälder med gamla föräldern och barnet som nya barn. Maps 31
Borttagning i AVL-träd Borttagning: som i binära sökträd Om obalans uppkommer omstrukturera med rotationer! Omstrukturering i delträd kan ge upphov till obalans högre upp vi kan behöva omstrukturera flera gånger Jfr: insättning räcker att omstrukturera en gång (kring nedersta obalanserade noden)! Maps 32
Splayträd Binärt sökträd Behöver ej vara balanserade som AVLträd Nycklar som man ofta letar efter skall ligga högt upp i trädet 90-10-regeln: 90% av sökningar är efter 10% av nycklarna Maps 33
Splayträd Insättning, sökning och borttagning som i vanligt binärt sökträd, följda av en splay, dvs man omstrukturerar trädet så att den sist besökta nyckeln placeras i roten. Den amorterade kostnaden är O(log n). Ingen ombalansering som i AVL-träd (eller som i (2,4)-träd eller ommålning som i rödsvarta träd, mer senare). Maps 34
Zig-zig Maps 35
Zig-zag (jfr dubbelrotation) Maps 36
Zig Maps 37
Exempel: sätt in 11 5 5 3 9 3 9 8 12 8 12 10 10 11 Maps 38
Exempel: sätt in 11 zig zag 3 5 9 8 12 3 5 9 8 11 10 11 10 12 Maps 39
Exempel: sätt in 11 zig zig 5 11 3 9 9 12 8 11 5 10 10 12 3 8 Maps 40
Enkellänkade binära träd En nod innehåller Pekare till element (elementet självt om primitiv typ) Pekare till vänster barn Pekare till höger barn A B D C E Maps 41
Att lagra binära träd i fält exempel 2 Ett binärt träd 5 6 Samma träd lagrat i ett fält 9 7 2 5 6 9 7 Maps 42
Att lagra binära träd i fält - exempel 0 Ett binärt träd 1 2 Samma träd lagrat i ett fält 3 5 6 0 1 2 3 5 6 8 8 Maps 43
Att lagra binära träd i fält allmän princip Roten lagras i cell 0 Om en viss nod lagras i cell i så lagras - vänster barn i cell 2i + 1 - höger barn i cell 2i + 2 (Obs. G&T lägger roten i 1 och barnen i 2i och 2i + 1) Ett binärt träd är fullständigt om dess n noder lagras i cellerna 0,, n-1. Om fullständiga binära träd lagras i fält har inga tomma mellanrum! Obs. Om våra träd växer kan vi behöva dynamiska (utvidgbara) fält! Maps 44
(2,4)-träd 9 2 5 7 10 14 Maps 45
Ett (2,4)-träd till 11 2 6 8 27 32 1 3 5 7 10 13 17 23 30 34 Maps 46
(2,4)-träd Varje nod lagrar 1-3 nycklar (+ värden) En inre nod som lagrar n nycklar har n+1 barn Alla löv ligger på samma djup (ett exakt balanserat träd)! Sökträdsegenskapen gäller: de n nycklarna i en nod separerar nycklarna i de n+1 delträden (se nästa bild, boken ger den allmänna egenskapen) Maps 47
(2,4)-träd har sökträdsegenskap 2, 8 är mindre än 10 12 ligger mellan 10 och 15 18 ligger mellan 15 och 24 27, 32 är större än 24 10 15 24 2 8 12 18 27 32 Maps 48
Sökning i (2,4)-träd Exempel: sök efter 30! 11 24 2 6 8 15 27 32 30 saknas Maps 49
Insättning Kan ge upphov till overflow. Vi måste då splittra en nod (se boken) Exempel: insättning av 30 orsakar overflow nedan: 10 15 24 2 8 12 18 v 27 32 35 10 15 24 Sätt in 30 2 8 12 18 27 30 32 35 Maps 50 v overflow
Röd-svarta träd v 6 3 8 4 z Maps 51
Rödsvarta träd: binära sökträd som representerar (2,4)-träd Ett röd-svart träd är ett binärt sökträd vars noder är färgade röda eller svarta Så här gör man om (2,4)-träd till rödsvarta träd: 4 3 5 2 6 7 4 5 3 6 3 eller 5 2 7 Maps 52
Röd-svarta träd Roten är svart Barnen till en röd nod är svarta Alla löv har samma svart-djup, dvs samma antal svarta förfäder (inklusive lövet självt). Detta motsvarar balanseringskravet på (2,4)-träd. 9 4 15 2 6 12 21 7 Maps 53
Insättning i röd-svarta träd 1. Använd först algoritmen för insättning i binära sökträd! 2. Färga den nya noden röd (undantag: den nya noden är rot)! 3. Vi kan då få en dubbel röd strukturera om eller måla om! 9 4 15 2 6 12 21 7 13 dubbel röd ny nod Maps 54
Ommålning Poängen med röd-svarta träd är att det är billigare att måla om än att omstrukturera trädet som man gör med (2,4)-träd! (Jfr hur man handskas med overflow i (2,4)- träd.) 9 måla röd 4 2 6 12 7 13 15 21 måla svart måla svart Maps 55
Omstrukturering Gör en enkelrotation (som i AVL-träd) av 6,7, 8! 7 blir svart med de röda barnen 6 och 8. (Jfr sambandet med (2,4)-träd. Vi behöver här bara se till att vi får en korrekt röd-svart representation av en 4-nod!) 9 4 15 2 6 12 21 dubbel röd 7 8 ny nod Maps 56
Några effektiva implementeringar av lexika Sökning Insättning Borttagning Kommentar AVL-träd (2,4)-träd O(log n) O(log n) O(log n) -omstruktureringskostnader Skiplistor O(log n) i medeltal O(log n) i medeltal O(log n) i medeltal -slumpmässig algoritm Röd-svarta träd O(log n) O(log n) O(log n) -Ommålning men inte mycket omstrukturering! -TreeMap i Java Maps 57
Några effektiva implementeringar av lexika Sökning Insättning Borttagning Kommentar Splayträd O(log n) amorterad O(log n) amorterad O(log n) amorterad -effektivt för vanligaste nycklar B-träd O(log B n) I/O O(log B n) I/O O(log B n) I/O -för stora lexika/databaser Maps 58
B-träd för sökning i externminne Om vår datasamling (mängd, lexikon) inte får plats i primärminnet måste vi lagra delar av den på externminne Tiden det tar för sökningar, insättningar och borttagningar beror huvudsakligen på antalet dataöverföringar från externminnet B-träd generaliserar (2,4)-träd, i stället för noder med mellan 2 och 4 barn har det noder med mellan d/2 och d barn. Storleken d kan vara ett block i externminnet. Maps 59