Föreläsning 6 Sökträd: AVL-träd, ”Multi-Way”-sökträd, B-träd TDDC70/91: DALG Utskriftsversion av föreläsning i Datastrukturer och algoritmer 23 september 2013 Tommy Färnqvist, IDA, Linköpings universitet 6.1 Innehåll Introduktion find,insert och remove i ett binärt sökträd tar O(h) tid, där h är höjden av trädet. Håll sökträdet balanserat!! 6.2 Innehåll 1 AVL-träd 1 2 (2, 3)-träd 13 3 15 1 B-träd 6.3 AVL-träd AVL-träd • • • • Självbalanserande BST/höjdbalanserat BST AVL = Adelson-Velskii och Landis, 1962 Idén: Håll reda på balansinformation i varje nod AVL-egenskapenFör varje intern nod v i T skiljer sig höjden av barnen till v med högst 1 . . . eller alternativt. . . För varje intern nod v i T gäller att b(v) ∈ {−1, 0, 1}, där b(v) = height(leftChild(v)) − height(rightChild(v)) 6.4 Maximal höjd av AVL-träd Proposition 1 (10.2 i kursboken). Höjden av ett AVL-träd som lagrar n poster är O(log n). Vilket får som följd att. . . Proposition 2. Vi kan göra find, insert och remove i ett AVL-träd i tid O(log n) medan vi bevarar AVLegenskapen. 6.5 1 Exempel: ett AVL-träd 6.6 44 17 3 1 78 2 0 0 1 32 50 88 0 48 0 62 Insättning i ett AVL-träd • Den nya noden gör att trädhöjden förändras och att trädet måste höjdbalanseras. – Man kan hålla reda på delträdens höjd på olika sätt: ∗ Lagra höjden explicit i varje nod ∗ Lagra balansfaktorn för noden • Förändringen brukar beskrivas som en höger- eller vänsterrotation av ett delträd. • Det räcker med en rotation för att få trädet i balans igen. 6.7 Insättning i AVL-träd (enkla fall) 6.8 Insättningsalgoritm • Starta från den nya noden och leta uppåt tills man hittar en nod x s.a. dess ”grandparent” z är obalanserad. Markera x:s förälder med y. • Gör en rekonstruering av trädet så här: – Döp om x, y, z till a, b, c baserat på deras inorder-ordning. – Låt T0 , T1 , T2 , T3 vara en uppräkning i inorder av delträden till x, y och z. (Inget av delträden får ha x, y eller z som rot.) – z byts mot b, dess barn är nu a och c. – T0 och T1 är barn till a och T2 och T3 är barn till c. 6.9 2 Exempel: insättning i ett AVL-träd 6.10 44 4 z/c 17 1 78 3 y/a 0 32 0 2 T3 88 50 x/b 0 1 48 T0 62 T1 54 Exempel: insättning i ett AVL-träd 44 T0 17 6.11 b 3 1 a T1 c T2 T3 62 2 0 1 1 32 78 50 0 0 0 54 48 88 Fyra olika rotationer b=y a=z enkel rotation b=y a=z c=x c=x T3 T0 T1 T3 T0 T1 T2 T2 Om b = y kallas det en enkel rotation.”Rotera upp y över z” 6.12 Fyra olika rotationer b=y c=z enkel rotation a=x b=y c=z a=x T0 T2 T0 T3 T1 T2 T3 T1 Om b = y kallas det en enkel rotation.”Rotera upp y över z” 3 6.13 Fyra olika rotationer b=x a=z dubbel rotation c=y a=z c=y b=x T2 T0 T2 T3 T0 T1 T3 T1 Om b = x kallas det en dubbel rotation.”Rotera upp x över y och sedan över z” 6.14 Fyra olika rotationer b=x c=z dubbel rotation a=y a=y c=z b=x T0 T3 T1 T1 T0 T2 T3 T2 Om b = x kallas det en dubbel rotation.”Rotera upp x över y och sedan över z” 6.15 Ett annat sätt att beskriva det på y x T2 T0 T1 Antag att vi har balans. . . 6.16 Ett annat sätt att beskriva det på 4 y x T2 T1 T0 . . . och sedan stoppar in något som sabbar den 6.17 Ett annat sätt att beskriva det på y x T2 T1 T0 Gör en enkel rotation 6.18 Ett annat sätt att beskriva det på y x T2 T1 T0 5 Gör en enkel rotation 6.19 Ett annat sätt att beskriva det på y x T2 T1 T0 Gör en enkel rotation 6.20 Ett annat sätt att beskriva det på x y T1 T20 T0 Gör en enkel rotation 6.21 Ett annat sätt att beskriva det på 6 x y T0 T1 T20 Gör en enkel rotation 6.22 Ett annat sätt att beskriva det på x y T0 T1 T20 Klart! 6.23 Ett annat sätt att beskriva det på z y 7 Ett nytt exempel. . . 6.24 Ett annat sätt att beskriva det på z y . . . den här gången stoppar vi in något på ett annat ställe 6.25 Ett annat sätt att beskriva det på z y Prova en enkel rotation igen. . . 6.26 Ett annat sätt att beskriva det på 8 y z . . . hmm, vi har inte fått balans 6.27 Ett annat sätt att beskriva det på z y Börja om från början. . . och titta på strukturen i y Ett annat sätt att beskriva det på z y T3 x T0 T1 T2 9 6.28 Vi får lov att göra en dubbel rotation 6.29 Ett annat sätt att beskriva det på z y T3 x T0 T1 T2 Vi får lov att göra en dubbel rotation 6.30 Ett annat sätt att beskriva det på z y T3 x T0 T1 T2 Vi får lov att göra en dubbel rotation 6.31 Ett annat sätt att beskriva det på 10 z y T3 x T0 T1 T2 Vi får lov att göra en dubbel rotation 6.32 Ett annat sätt att beskriva det på z y T3 x T0 T1 T2 Vi får lov att göra en dubbel rotation 6.33 Ett annat sätt att beskriva det på x y T0 z T1 T2 T3 11 Vi får lov att göra en dubbel rotation 6.34 Ett annat sätt att beskriva det på x y T0 z T1 T2 T3 Klart! 6.35 Trenodsrekonstruering = rotationer. . . Vissa författare använder vänster- och högerrotationer: Enkel vänsterrotation: • vänstra delen av delträdet (a och j) sänks ner • vi har ”roterat (upp) b över a” a b b j a c k l m j c k m l 6.36 Dubbla rotationer. . . Två rotationer behövs när noderna som ska balanseras om är placerade i ett sicksackmönster. • Rotera upp b över a • Rotera upp b över c c a k b a a b j c b m j k l l m j c k l m 6.37 12 Borttagning i ett AVL-träd • find och remove som i ett vanligt binärt sökträd • Uppdatera balansinformationen på väg tillbaka upp till roten • Om för obalanserat: Strukturera om . . . men. . . – När vi återställer balansen på ett ställe kan det uppstå obalans på ett annat – Måste upprepa balanseringen (eller kontroll av balansen) till dess vi når roten – Högst O(log n) ombalanseringar 6.38 2 (2, 3)-träd Ny approach: släpp på något av kraven • AVL-träd: binärt träd, accepterar viss (liten) obalans. . . • Kom ihåg: Fullt binärt träd: icke-tomt; graden är antingen 0 eller 2 för varje nod Perfekt binärt träd: fullt, alla löv har samma djup • Kan vi bygga och underhålla ett perfekt träd (om vi struntar i ”binärt”)? Då skulle vi alltid känna till söktiden i värsta fall exakt! 6.39 (2, 3)-träd Förut: • Ett ”pivotelement” • Om större letar vi till höger • Om mindre letar vi till vänster Nu: • Tillåt flera (nämligen 1–2) ”pivotelement” • Antalet barn till en intern nod är antalet pivotelement + 1 (dvs 2–3) 5 2 8 5 10 2 8 12 6.40 Mer generellt (a, b)-träd • Varje nod är antingen ett löv eller så har den c barn, där a ≤ c ≤ b Varje nod har mellan a − 1 och b − 1 pivotelement • 2 ≤ a ≤ (b + 1)/2 (men roten behöver bara ha minst två barn (eller inga) även när a > 2 gäller) • find fungerar ungefär som förut • insert måste kolla att noden inte blivit överfull (i så fall måste noden delas upp) • remove kan leda till att man måste slå ihop noder eller föra över värden mellan noder Proposition 3 (14.1 i kursboken). Höjden av ett (a, b)-träd som lagrar n dataelement är Ω(log n/ log b) och O(log n/ log a). ⇒ Plattare träd, men mer jobb i noderna. 6.41 13 Insättning i ett (a, b)-träd med a = 2 och b = 3 5 Insert(10) 5 10 Insert(15) 10 5 Insert(18) 15 • Så länge det finns plats i barnet vi hittar, lägg till elementet i det barnet. . . • Om fullt, dela upp och tryck det utvalda pivotelementet uppåt. . . . . . detta kan hända upprepade gånger 10 5 10 Insert(17) 15 18 5 10 17 15 17 18 5 15 18 6.42 Borttagning i (2, 3)-träd Tre fall: • Inga villkor bryts genom borttagning • Ett löv tas bort (blir tomt) För då över någon annan nyckel till det lövet, . . . ok om vi har syskon med 2+ element 20 ? 10 17 5 15 Överföring av 30 och 35 30 Delete(25) 30 18 25 10 17 ? 35 40 20 35 40 30 5 35 40 15 35 18 30 40 6.43 Borttagning i (2, 3)-träd • Om ett löv tas bort (blir tomt) • För då över någon annan nyckel till det lövet, eller • Slå ihop det med en granne 10 17 20 Delete(18) 10 17 5 15 5 35 18 30 15 ? 20 10 10 40 5 15 17 5 35 15 17 30 40 6.44 14 Borttagning i (2, 3)-träd • En intern nod blir tom Roten: ersätt med föregångare eller efterföljare i inorder Reparera sedan inkonsistenser med lämpliga ihopslagningar och överföringar. . . Ersätt... ...slå ihop löv Delete(20) ? 20 10 5 3 17 För få element internt... ...slå ihop noder 10 35 30 40 5 17 ? ? 35 17 30 40 35 5 10 30 17 35 40 5 10 30 40 6.45 B-träd B-träd • • • • Används för att upprätthålla ett index över externt data (t.ex. innehållet på ett skivminne) Är ett (a, b)-träd där a = db/2e, dvs b = 2a − 1 Vi kan nu välja b så att en full nod precis tar upp ett block på skivminnet Genom att välja a = db/2e kommer vi alltid att fylla ett helt block på skivminnet när två block slås samman! • B-träd (och varianter) används i många filsystem och databaser – Windows: HPFS – Mac: HFS, HFS+ – Linux: ReiserFS, XFS, Ext3FS, JFS – Databaser: ORACLE, DB2, INGRES, PostgreSQL 6.46 15