Bináris keresőfa Felépítés, alapvető műveletek előadás http://nik.uni-obuda.hu/prog2 Szénási Sándor szenasi.sandor@nik.uni-obuda.hu Óbudai Egyetem,Neumann János Informatikai Kar
Bináris keresőfa Rekurzív típusok, fa adatszerkezet Bejárás és keresés Beszúrás művelete Törlés művelete
3 Fa definíciója Fa (Tree): csomópontok (nodes) halmaza, amelyeket élek (edges) kötnek össze, és teljesülnek az alábbi feltételek: létezik egy kitüntetett csomópont: a gyökér (root) a gyökértől különböző minden más c csomópont egy éllel van összekötve a szülőjéhez a fa összefüggő: bármely nem-gyökér csomóponttól kiindulva a szülőkön keresztül a gyökérhez eljutunk Gráfelmélet alapján fa definíciója: olyan gráf, amelyik összefüggő, nem tartalmaz kört
4 Alapfogalmak Ha (v, w) E, akkor v-t a w szülőjének, w-t pedig a v gyerekének nevezzük u F=(V,E) Ha u-ból vezet út w-be, akkor u a w őse, w az u leszármazottja Ha u w, akkor valódi ős illetve leszármazott v w x s y z Valódi leszármazottal nem rendelkező csomópont a fa levele Egy s csomópont az összes leszármazottjával együtt F részfáját alkotja. Ennek gyökere s Erdő: Fák együtteséből álló irányított gráf
5 Fa további jellemzői Csomópont mélysége: a gyökértől a hozzá elvezető út hossza Csomópont magassága: annak az innen kiinduló útnak a hossza, amelyik a leghosszabb a levelekig vezető utak közül Fa magassága: a gyökér magassága Csomópont szintje: a fa magassága a csomópont mélysége
6 Rekurzív típusok Az adatszerkezetek egy része jól leírható egy rekurzív szerkezettel is, ami fizikailag hasonló tárolást, de egészen más algoritmusokat eredményezhet TLista = Struktúra(tartalom, következő) A lista rekurzív értelmezése szerint minden eleme felfogható egy tartalom résszel, és egy másik (a következő mutató által mutatott elemmel kezdődő) listával rendelkező szerkezetként TFa = Struktúra(tartalom, fák) Egy fa egy eleme leírható egy tartalom résszel, és további részfákkal rendelkező struktúrával TBinárisFa = Struktúra(tartalom, balfa, jobbfa) A bináris fa egy olyan fa, amely legfeljebb két másik fát tartalmazhat
7 Bináris fa eleme Bináris fa egy elemének a definíciója: TBinFaElem = Struktúra(tartalom, balgyerek, jobbgyerek) Tartalom mező mező neve: tart típusa: T ez a típus lehet a láncolt listához hasonlóan egyszerű típus összetett típus objektum referencia Gyerek hivatkozások mezők nevei: bal és jobb ezek típusa: M ez a típus a láncolt listához hasonlóan implementációfüggő itt is használunk egy speciális üres jelet ( ) Egy gyökér nevű külső változó hivatkozik a fa első elemére A csomóponton belül egyéb mezők is lehetnek, pl. gyakran tároljuk a szülő címét is
8 Példa bináris fára Aritmetikai kifejezés fa: gyökér + * 2 / x - y 10 6 z Értelmezése Levelek: operandusok Csomópontok: operátorok Fenti kifejezés: (x + (y 10)) * 2 * (6 / z)
9 Bináris keresőfa eleme Bináris keresőfa (BST) egy elemének a definíciója: TBinFaElem = Struktúra(kulcs, tartalom, balgyerek, jobbgyerek) Kulcs tulajdonság tulajdonság neve: kulcs típusa: K ez a tulajdonság a láncolt listához hasonlóan lehet külön mező a tartalom egy része maga a tartalom Kulcs alapján rendezett: a fa minden r csomópontjára igaz, hogy r baloldali részfája legfeljebb r.kulcs nagyságú, r jobboldali részfája pedig legalább r.kulcs nagyságú kulcsokat tartalmaz A rendezés természetesen lehet fordított is Későbbi algoritmusainkban feltételezzük a kulcsok egyediségét
10 Példa bináris keresőfára Egész számokat tároló keresőfa, ahol kulcs = tartalom: Megjegyzések: gyökér 30 20 40 10 25 5 15 az ábrákon mindig azonos kulcsot és tartalmat feltételezünk, de az algoritmusokban ezeket külön kezeljük a későbbiekben a záró -eket nem jelöljük, az algoritmusokban azonban számítunk ezekre üres fa esetén: gyökér = 50 45 60 55
Bináris keresőfa Rekurzív típusok, fa adatszerkezet Bejárás és keresés Beszúrás művelete Törlés művelete
12 Bináris fa bejárások Bejárás: az adatszerkezet valamennyi elemének egyszeri elérése (feldolgozása) A láncolt listához hasonlóan a bejárás algoritmusa független a végrehajtandó tevékenységtől, ezért ez utóbbira csak utalást teszünk Mivel a láncolt listával ellentétben egy elemből több irányba is tovább lehet lépni, többféle bejárás is elképzelhető A csomópontokban található adatok (tartalom, bal, jobb) feldolgozásának sorrendje alapján három fő változat különböztethető meg (ezen belül a bal és jobb megcserélhető): Preorder bejárás: tartalom, bal, jobb Inorder bejárás: bal, tartalom, jobb Postorder bejárás: bal, jobb, tartalom Valójában mindhárom algoritmus azonos sorrendben éri el az elemeket, csak a feldolgozás ideje különböző Itt nem használjuk ki a rendezettséget, tehát a kulcs-nak nincs szerepe
Preorder bejárás szenasi.sandor@nik.uni-obuda.hu 13 Preorder bejárás algoritmusa eljárás PreorderBejárás(p) ha p akkor FELDOLGOZ(p.tart) Bejárás indítása PreorderBejárás(p.bal) PreorderBejárás(p.jobb) elágazás vége eljárás vége PreorderBejárás(gyökér) rekurzió teljes fa bejárása PreorderBejárás(p) részfa bejárása Gyakorlati alkalmazás: fa elmentése
Inorder bejárás szenasi.sandor@nik.uni-obuda.hu 14 Inorder bejárás algoritmusa eljárás InorderBejárás(p) ha p akkor InorderBejárás(p.bal) Bejárás indítása FELDOLGOZ(p.tart) InorderBejárás(p.jobb) elágazás vége eljárás vége InorderBejárás(gyökér) rekurzió teljes fa bejárása InorderBejárás(p) részfa bejárása Gyakorlati alkalmazás: elemek elérése rendezés szerinti sorrendben (növekvő vagy csökkenő)
Preorder bejárás szenasi.sandor@nik.uni-obuda.hu 15 Postorder bejárás algoritmusa eljárás PostorderBejárás(p) ha p akkor PostorderBejárás(p.bal) Bejárás indítása PostorderBejárás(p.jobb) FELDOLGOZ(p.tart) elágazás vége eljárás vége PostorderBejárás(gyökér) rekurzió teljes fa bejárása PostorderBejárás(p) részfa bejárása Gyakorlati alkalmazás: fa felszabadítása
16 Keresés bináris keresőfában Az általános keresés (tetszőleges feltételnek megfelelő tartalom keresése) az előzőleg megismert bejárások segítségével valósítható meg Megadott kulcsú elem keresésekor már ki tudjuk használni a fa rendezettségét: a fa gyökérelemének kulcsa vagy egyenlő a keresett kulccsal, vagy egyértelműen meghatározza, hogy melyik részfában kell a keresést folytatni Ez ugyanúgy igaz a teljes bináris fa gyökérelemére, illetve bármelyik (a keresés során elért) részfájának gyökerére A rekurzív keresés menete (p gyökerű (rész)fában keressük az x-et) triviális megoldás ha p üres, akkor x nincs a fában ha p kulcsa x, akkor megtaláltuk indukció ha p kulcsa kisebb mint x, akkor x-et a jobb részfában, ha p kulcsa nagyobb mint x, akkor a bal részfában keressük.
Keresés algoritmusa szenasi.sandor@nik.uni-obuda.hu 17 Kulcs alapján keresés függvény Keresés(p, kulcs) ha p akkor ha p.kulcs > kulcs akkor vissza Keresés(p.bal, kulcs) különben különben ha p.kulcs < kulcs akkor vissza Keresés(p.jobb, kulcs) különben vissza p.tart elágazás vége hiba nincs ilyen kulcs elágazás vége függvény vége Átlagos lépésszám (kiegyensúlyozott fában): O(log 2 n) Ez azonban jelentősen függ a fa felépítésétől
Bináris keresőfa Rekurzív típusok, fa adatszerkezet Bejárás és keresés Beszúrás művelete Törlés művelete
19 Beszúrás bináris keresőfába A beszúrás során az elem beláncolásán kívül ügyelnünk kell a keresőfa tulajdonság fenntartására is Ugyanazok az elemek többféleképpen is elhelyezkedhetnek egy bináris keresőfában, beszúráskor ez alapján több stratégiánk is lehet minél kisebb erőforrásigényű legyen a beszúrás minél kiegyensúlyozottabb legyen a fa a beszúrás(ok) után Mi olyan beszúrást használunk, ahol nem kell átmozgatni a már meglévő elemeket az új elem felvételekor A rekurzív beszúrás menete (p gyökerű (rész)fába szúrjuk az x-et) triviális esetek ha p üres, akkor új x kulcsú csomópontot veszünk fel, ami a gyökér lesz ha p nem üres, és a kulcsa x, akkor hibát jelzünk indukció ha p kulcsa kisebb mint x, akkor x-et a jobb részfába, ha p kulcsa nagyobb mint x, akkor a bal részfába szúrjuk be.
Beszúrás algoritmusa szenasi.sandor@nik.uni-obuda.hu 20 Új elem beszúrása eljárás Beszúrás(címsz. p, kulcs, érték) ha p = akkor p LÉTREHOZ(M) p.kulcs kulcs; p.tart érték; p.bal ; p.jobb különben ha p.kulcs > kulcs akkor Beszúrás(p.bal, kulcs, érték) különben ha p.kulcs < kulcs akkor Beszúrás(p.jobb, kulcs, érték) különben hiba már van ilyen kulcs elágazás vége elágazás vége elágazás vége eljárás vége
Bináris keresőfa Rekurzív típusok, fa adatszerkezet Bejárás és keresés Beszúrás művelete Törlés művelete
22 Törlés bináris keresőfából A törlés során az elem kiláncolásán kívül ügyelnünk kell a keresőfa tulajdonság fenntartására is Törlés során az alábbi problémák merülhetnek fel két gyerekkel rendelkező elem mindkét gyerekét nem tudjuk az ő szülőjének egy mutatójára rákapcsolni gyökérelem törlése A rekurzív törlés menete (p gyökerű (rész)fából töröljük az x-et) triviális esetek ha p üres, akkor hibát jelzünk ha p nem üres, és a kulcsa x, akkor töröljük, majd helyreállítjuk a BST-t indukció ha p kulcsa kisebb mint x, akkor x-et a jobb részfából, ha p kulcsa nagyobb mint x, akkor a bal részfából töröljük. A BST helyreállítás menete attól függ, hogy hány gyereke van p-nek Egy sincs (levél) Egy gyerek Két gyerek
23 BST tulajdonság helyreállítása 1. eset Ebben az esetben a törlendő csúcspont egy levél, tehát nincsenek gyerek elemei Itt elhagyjuk a törlendő kulcsot tartalmazó elemet, a szülő megfelelő mutatóját pedig -ra állítjuk Pl. töröljük a 70-et 30 30 50 50 40 60 40 60 35 45 70 35 45 42 42
24 BST tulajdonság helyreállítása 2. eset A törlendő csúcspontnak csak egy bal vagy csak egy jobb oldali gyereke van Ilyenkor a láncolt listákhoz hasonlóan ki tudjuk láncolni a törlendő kulcsot tartalmazó elemet Pl. töröljük a 60-at 30 30 50 50 40 60 40 70 35 45 70 35 45 42 42
25 BST tulajdonság helyreállítása 3. eset Ilyenkor a törlendő csúcspontnak bal és jobb oldali gyereke is van Ebben az esetben a szükséges lépések: Megkeressük a baloldali részfa legjobboldalibb elemét Ennek tartalmát és kulcsát felmásoljuk a törlendő elembe Majd ezt az elemet töröljük (ennek biztos nincs jobboldali gyereke) Pl. töröljük az 50-et 30 30 50 45 40 60 40 60 35 45 70 35 42 70 42
26 Törlés algoritmusa Megadott kulcsú elem törlése eljárás Törlés(címsz. p, kulcs) ha p akkor ha p.kulcs > kulcs akkor Törlés(p.bal, kulcs) különben ha p.kulcs < kulcs akkor Törlés(p.jobb, kulcs) különben ha p.bal = akkor q = p; p p.jobb; FELSZABADÍT(q) különben ha p.jobb = akkor q = p; p p.bal; FELSZABADÍT(q) különben TörlésKétGyerek(p, p.bal) elágazás vége elágazás vége elágazás vége elágazás vége különben hiba Nincs ilyen elem elágazás vége eljárás vége
Törlés algoritmus két gyerek kezelése szenasi.sandor@nik.uni-obuda.hu 27 eljárás TörlésKétGyerek(e, címsz. r) ha r.jobb akkor TörlésKétGyerek(e, r.jobb) különben e.tart r.tart e.kulcs r.kulcs q r r r.bal FELSZABADÍT(q) elágazás vége eljárás vége Baloldali részfa legjobboldalibb elemének megkeresése, és ennek tartalmával felülírjuk a törlendő elemet Ez tulajdonképpen a törlendőnél kisebb kulcsok közül a legnagyobb Ezt megtehetjük, hiszen ez biztosan nagyobb, mint a baloldali elemek és biztosan kisebb, mint a jobboldali elemek
28 Miért használjuk? A bináris fa előnyei rendezett ebből adódóan gyors keresés relatív gyors elem felvétel relatív gyors elem törlés, legrosszabb esetben sincs szükség a fa nagy részének átalakítására a csomópontok tartalma gyakran egy más adatszerkezet elemére mutat: ideális indexelésre kiegészítő adatszerkezetként A bináris fa hátrányai bonyolult, lásd bejárások rekurzióval a műveletek költségesek, illetve maga a rekurzió az OOP nyelvekben gyakran életidegen módon jelenik meg elemek nem érhetőek el közvetlenül (sőt, maga az indexelés sem egyértelmű, csak a bejárás módjával együtt) a gyors keresés nem garantált, csak kiegyensúlyozott fákban valósul meg a két gyerek címe miatt nagy lehet egy elem helyfoglalása
29 Kiegyensúlyozatlan fák problémája Vizsgáljuk meg az alábbi kettő, adattartalom szempontjából azonos, de szerkezetileg más fákat keresés szempontjából 40 50 60 35 40 45 35 45 55 65 50 55 60 65 A jobboldali (elfajult) fa keresési szempontból nem ideális, láncolt listához hasonló lépésszámot igényel Egyéb fa szerkezetek: piros-fekete fa, B-fa
30 Kiegyensúlyozottság Kiegyensúlyozott fa: legfeljebb egy szintnyi (mélység) eltérés van az egyes (azonos szinten található) részfái között Teljesen kiegyensúlyozott fa: minden csúcsából leágazó bal- és jobboldali részfa csúcsainak száma legfeljebb egyel különbözik egymáshoz képest Teljes fa: Minden csúcsból leágazó bal- és jobboldali részfa csúcsainak száma azonos Célunk: a módosító algoritmusok kiegészítése, hogy minél inkább kiegyensúlyozott (az előző oldalon látható bal oldalihoz hasonló) fák építésére törekedjenek Ennek egy lehetséges megoldása, ha a beszúrás és törlés után a fa szerkezetét megváltoztatjuk, például forgatásokkal
31 Forgatás Forgatás: olyan lokális művelet, amely megváltoztatja a fa szerkezetét, de megőrzi a rendezettséget Megkülönböztetünk balra-, illetve jobbraforgatás műveletet eljárás Balra-forgat(x) y x.jobb x.jobb y.bal ha y.bal akkor y.bal.szülő x elágazás vége y.szülő x.szülő ha x.szülő = akkor gyökér y különben ha x.szülő.bal = x akkor x.szülő.bal = y különben x.szülő.jobb = y elágazás vége elágazás vége y.bal x x.szülő y eljárás vége
32 Piros-fekete fa Piros-fekete fa: Olyan bináris keresőfa, amely rendelkezik az alábbi tulajdonságokkal: minden csúcs színe piros vagy fekete minden levél színe fekete minden piros csúcsnak mindkét gyereke fekete bármely két, azonos csúcsból kiinduló és levélig vezető úton ugyanannyi fekete csúcs van (fekete magasság) Megvalósítással kapcsolatos megjegyzések: a BST struktúrát kiegészítjük egy új attribútummal, ami jelzi a színt (értéke csak piros vagy fekete lehet) az egyszerűbb algoritmusok miatt tároljuk a csomópontok szüleit is (a gyökérpont esetén ezt -el jelöljük) az egyszerűbb algoritmusok miatt a tartalommal külön nem foglalkozunk, feltételezzük, hogy amennyiben a kulcsot átmásoljuk, az mindig a kulccsal együtt mozog
33 Piros-fekete fa példa Piros-fekete fa 25 18 10 22 20 24 40 30 50 28 32 48 60 Megjegyzés: levélnek a nem ábrázolt értékeket tekintjük (ezek kötelezően feketék) Megközelítőleg kiegyensúlyozott: biztosítható, hogy bármely, a gyökértől levélig vezető út hossza nem nagyobb, mint a legrövidebb ilyen út hosszának a kétszerese
34 Irodalomjegyzék Javasolt/felhasznált irodalom Aho, Hopcroft, Ulmann: Számítógép-algoritmusok tervezése és analízise, Műszaki Könyvkiadó, 1982 Cormen, Leiserson, Rivest: Algoritmusok, Műszaki Könyvkiadó, 1997 Knuth: A számítógép programozás művészete 3. kötet. Keresés és rendezés, Műszaki Könyvkiadó, 1988 Kotsis, Légrádi, Nagy, Szénási: Többnyelvű programozástechnika, Panem Könyvkiadó, 2007 Pap, Szlávi, Zsakó: μlógia27 Módszeres programozás: Rekurzív típusok, ELTE TTK, 1998 Szénási: Algoritmusok, adatszerkezetek II., Óbudai Egyetem, 2014