Puna-musta puu | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Tyyppi | hakupuu | |||||||||||||||
Keksintövuosi | 1972 | |||||||||||||||
Tekijä | Rudolf Baier | |||||||||||||||
Monimutkaisuus O - symboleissa | ||||||||||||||||
|
||||||||||||||||
Mediatiedostot Wikimedia Commonsissa |
Punamusta puu ( eng. red-black tree , RB tree ) on yksi itsetasapainottuvien binäärihakupuiden tyypeistä, joka takaa puun korkeuden logaritmisen kasvun solmujen lukumäärästä ja mahdollistaa nopean perushakupuun suorittamisen toiminnot: solmun lisääminen, poistaminen ja etsiminen. Tasapaino saavutetaan ottamalla käyttöön puusolmun lisäattribuutti - "värit". Tämä attribuutti voi ottaa yhden kahdesta mahdollisesta arvosta - "musta" tai "punainen".
Saksalaista keksijää Rudolf Bayeria pidetään punamustan puun keksijänä . Tietorakenteelle annettiin nimi "punamusta puu" L. Gimbasin ja R. Sedgwickin artikkelissa (1978). Gimbasin mukaan he käyttivät kaksivärisiä kyniä [1] . Sedgwickin mukaan punainen näytti parhaalta lasertulostimessa [1] [2] .
Punamustaa puuta käytetään vertailukelpoisten tietojen, kuten tekstin tai numeroiden, järjestämiseen. Punamustien puiden lehtisolmut eivät sisällä dataa, joten ne eivät vaadi muistin varaamista - riittää, että kirjoitat nollaosoittimen osoittimeksi esi-isolmussa olevaan lapseen. Joissakin toteutuksissa voidaan kuitenkin käyttää eksplisiittisiä lehtisolmuja algoritmin yksinkertaistamiseksi.
Punamusta puu on binäärihakupuu , jossa jokaisella solmulla on väriattribuutti . Jossa:
Näistä rajoituksista johtuen polku juuresta kaukaisimpaan lehteen on enintään kaksi kertaa pidempi kuin lähimpään ja puu on suunnilleen tasapainossa. Lisäys-, poisto- ja hakutoiminnot vaativat pahimmassa tapauksessa puun pituuteen verrannollisen ajan, mikä mahdollistaa punamustat puut olla tehokkaampia pahimmassa tapauksessa kuin perinteiset binäärihakupuut.
Tämän toiminnan ymmärtämiseksi riittää, kun tarkastellaan ominaisuuksien 4 ja 5 vaikutusta yhdessä. Olkoon mustien solmujen määrä juuresta lehteen B punamustalle puulle T. Tällöin lyhin mahdollinen polku mihin tahansa lehtiin sisältää B solmua, ja ne ovat kaikki mustia. Pidempi mahdollinen polku voidaan rakentaa sisällyttämällä punaiset solmut. Lauseesta 4 johtuen puussa ei kuitenkaan voi olla kahta punaista solmua peräkkäin ja lausekkeiden mukaisesti 2 ja 3, polku alkaa ja päättyy mustaan solmuun. Siksi pisin mahdollinen polku koostuu 2B-1-solmuista, vuorotellen punaisista ja mustista.
Jos sallit muun kuin lehtisolmun olla alle kaksi lasta ja lehtisolmun sisältää dataa, puu säilyttää perusominaisuudet, mutta sen kanssa työskentelyn algoritmeista tulee monimutkaisempia. Siksi artikkeli käsittelee vain "tyhmiä lehtisolmuja", jotka eivät sisällä tietoja ja jotka yksinkertaisesti osoittavat, mihin puu päättyy. Nämä solmut voidaan jättää pois joissakin kuvissa. Kohdasta 5 seuraa myös, että punaisen solmun jälkeläiset voivat olla joko kaksi mustaa välisolmua tai kaksi mustaa lehteä, ja ottaen huomioon kohdat 3 ja 4 - että jos yksi mustan solmun jälkeläisistä on lehtisolmu , toisen tulee olla joko myös arkki tai yllä kuvattu malli, jossa on yksi punainen ja kaksi arkkia.
Myös kirjallisuudessa on tulkinta, jossa ei itse solmut, vaan niihin johtavat reunat on maalattu punaisilla / mustilla väreillä - mutta tällä ei ole suurta merkitystä sen toimintaperiaatteen ymmärtämiselle.
Punamusta puu on rakenteeltaan samanlainen kuin B-puu parametrilla 4, jossa jokainen solmu voi sisältää 1 - 3 arvoa ja vastaavasti 2 - 4 osoitinta lapsille. Tällaisessa B-puussa kukin solmu sisältää vain yhden arvon, joka vastaa puna-mustan puun mustan solmun arvoa, valinnaisilla arvoilla ennen ja/tai sen jälkeen samassa solmussa, jotka molemmat vastaavat punamustan puun vastaaviin punaisiin solmuihin.
Yksi tapa nähdä tämä vastaavuus on "nostaa" punaisia solmuja punamustan puun graafisessa esityksessä niin, että ne ovat vaakasuorassa samassa tasossa mustien solmujen esivanhempiensa kanssa muodostaen sivun. B-puussa tai muokatussa graafisessa esityksessä punamusta puusta kaikilla lehtien solmuilla on sama syvyys.
Tämän tyyppinen B-puu on yleisempi kuin punamusta puu, vaikka, kuten näet, yhdestä tällaisesta B-puusta voidaan saada useita punamusta puita parametrilla 2. Jos B-puusivu sisältää vain yhden arvon, solmu on musta ja siinä on kaksi alapistettä. Jos sivulla on kolme arvoa, keskisolmu on musta ja jokainen sen naapuri on punainen. Jos sivulla on kuitenkin kaksi arvoa, mikä tahansa solmu voi muuttua mustaksi punamustapuussa (jolloin toinen on punainen).
Punamustat puut ovat käytännössä yksi yleisimmin käytetyistä itsetasapainottuvista hakupuista. Erityisesti useimpien C++ STL - kirjaston [3] , Java TreeMap -luokan [4] sekä monien muiden assosiatiivisten taulukkototeutusten useissa toteutuksissa eri kirjastoissa olevat set- ja karttasäilöt perustuvat punamustiin puihin.
Punamustat puut ovat suositumpia kuin täydellisesti tasapainotetut puut. jälkimmäisessä puusta poistamiseen ja tarvittavan tasapainon ylläpitämiseen voidaan käyttää liikaa resursseja. Lisäyksen tai poistamisen jälkeen tarvitaan uudelleenvärjäystoiminto, joka vaatii (O(log n ) tai O(1)) värinmuutoksia (mikä on käytännössä melko nopeaa) ja enintään kolme puun kiertoa (enintään kaksi lisäystä varten ). Vaikka insertio ja deleetio ovat monimutkaisia, ne ovat silti O(log n ) työvoimavaltaisia.
Punamustapuuhun lisätään uusi solmu yhden lehden tilalle, värjätty punaiseksi, ja siihen on kiinnitetty kaksi lehteä (koska lehdet ovat abstraktio, joka ei sisällä dataa, niiden lisääminen ei vaadi lisätoimintoa) . Mitä seuraavaksi tapahtuu, riippuu lähellä olevien solmujen väristä. Huomaa, että:
Jokainen tapaus on peitetty C - koodiesimerkeillä . Solmurakenteen määritelmä voi näyttää tältä:
enum solmun_värit { PUNAINEN , MUSTA }; struct solmu { struct solmu * vanhempi , * vasen , * oikea ; enum solmu_värit väri ; intkey ; _ };Nykyisen solmun setä ja isoisä löytyvät funktioilla:
rakennesolmu * _ isovanhempi ( struct solmu * n ) { if (( n != NULL ) && ( n -> vanhempi != NULL )) return n -> vanhempi -> vanhempi ; muu return NULL ; } rakennesolmu * _ setä ( struct solmu * n ) { struct solmu * g = isovanhempi ( n ); jos ( g == NULL ) return NULL ; // Ei isovanhempaa tarkoittaa ei setä jos ( n -> vanhempi == g -> vasen ) paluu g -> oikealle ; muu paluu g -> vasen ; }Puun kierto vasemmalle ja oikealle voidaan tehdä seuraavasti:
mitätön rotate_left ( struct solmu * n ) { struct solmu * pivot = n -> oikea ; pivot -> vanhempi = n -> vanhempi ; /* mahdollisesti puun juuren kääntäminen */ if ( n -> vanhempi != NULL ) { if ( n -> vanhempi -> vasen == n ) n -> vanhempi -> vasen = pivot ; muu n -> vanhempi -> oikea = pivot ; } n -> oikea = pivot -> vasen ; if ( pivot -> left != NULL ) pivot -> vasen -> vanhempi = n ; n -> vanhempi = pivot ; pivot -> vasen = n ; } mitätön rotate_right ( struct solmu * n ) { struct solmu * pivot = n -> vasen ; pivot -> vanhempi = n -> vanhempi ; /* mahdollisesti puun juuren kääntäminen */ if ( n -> vanhempi != NULL ) { if ( n -> vanhempi -> vasen == n ) n -> vanhempi -> vasen = pivot ; muu n -> vanhempi -> oikea = pivot ; } n -> vasen = pivot -> oikea ; if ( pivot -> right != NULL ) pivot -> oikealle -> vanhempi = n ; n -> vanhempi = pivot ; pivot -> oikea = n ; }Tapaus 1: Nykyinen solmu N on puun juuressa. Tässä tapauksessa se maalataan uudelleen mustaksi, jotta ominaisuus 2 (juuri on musta) pysyy oikeana. Koska tämä toiminto lisää yhden mustan solmun kuhunkin polkuun, ominaisuutta 5 (kaikki polut mistä tahansa solmusta lehtisolmuihin sisältävät saman määrän mustia solmuja) ei rikota.
mitätön insert_case1 ( struct solmu * n ) { if ( n -> vanhempi == NULL ) n -> väri = MUSTA ; muu insert_case2 ( n ); }Tapaus 2: Nykyisen solmun emo P on musta, eli ominaisuutta 4 (jokaisen punaisen solmun molemmat lapset ovat mustia) ei rikota. Tässä tapauksessa puu pysyy oikeana. Ominaisuutta 5 (kaikki polut mistä tahansa tietystä solmusta lehtisolmuihin sisältävät saman määrän mustia solmuja) ei ole rikottu, koska nykyisellä solmulla N on kaksi mustaa lehteä, mutta koska N on punainen, polku jokaiseen näistä lapsista sisältää saman mustien solmujen määrä, joka on polku mustaan lehteen, joka on korvattu nykyisellä solmulla, joten ominaisuus pysyy tosi.
mitätön insert_case2 ( struct solmu * n ) { if ( n -> vanhempi -> väri == MUSTA ) paluu ; /* Puu on edelleen voimassa */ muu insert_case3 ( n ); } Huomautus: Seuraavissa tapauksissa oletetaan, että N :llä on isovanhempi G , koska sen emo - P on punainen, ja jos se olisi juuri, se olisi musta. Siten N :llä on myös setä U , vaikka se voi olla lehtisolmu tapauksissa 4 ja 5.
Tapaus 3: Jos sekä vanhempi P että setä U ovat punaisia, ne voidaan molemmat värjätä mustiksi ja isovanhempi G muuttuu punaisiksi (ominaisuuden 5 säilyttämiseksi (kaikki polut mistä tahansa solmusta lehtisolmuihin sisältävät saman määrän mustia solmuja)) . Nyt nykyisellä punaisella solmulla N on musta emo. Koska minkä tahansa polun vanhemman tai sedän kautta täytyy kulkea isovanhemman kautta, mustien solmujen määrä näissä poluissa ei muutu. G :n isovanhempi voi kuitenkin nyt rikkoa ominaisuuksia 2 (juuri on musta) tai 4 (kunkin punaisen solmun molemmat lapset ovat mustia) (ominaisuutta 4 voidaan rikkoa, koska G :n vanhempi voi olla punainen). Tämän korjaamiseksi koko toimenpide suoritetaan rekursiivisesti G :lle tapauksesta 1. |
Tapaus 4: P :n vanhempi on punainen, mutta U :n setä on musta. Lisäksi nykyinen solmu N on P : n oikea lapsi , ja P puolestaan on esi-isänsä G vasen lapsi . Tällöin voidaan suorittaa puun kierto, joka muuttaa nykyisen solmun N ja sen esi -isän P rooleja . Käytä sitten päivitetyn rakenteen entiselle pääsolmulle P tapausta 5, koska ominaisuus 4 (mikä tahansa punaisen solmun molemmat alat ovat mustia) on edelleen rikottu. Kierto saa joitain polkuja (kaavion alipuussa, joka on merkitty "1") kulkemaan solmun N läpi , mitä ei aiemmin ollut. Tämä aiheuttaa myös sen, että jotkin polut (alipuussa, jonka nimi on "3") eivät kulje P -solmun läpi . Molemmat solmut ovat kuitenkin punaisia, joten kierto ei riko ominaisuutta 5 (kaikki polut tietystä solmusta lehtisolmuihin sisältävät saman määrän mustia solmuja). Ominaisuutta 4 rikotaan kuitenkin edelleen, mutta nyt ongelma on rajoittunut tapaukseen 5. |
Tapaus 5: Vanhempi P on punainen, mutta setä U on musta, nykyinen solmu N on P :n vasen lapsi ja P on G :n vasen lapsi . Tässä tapauksessa puuta pyöritetään G :llä . Tuloksena on puu, jossa entinen vanhempi P on nyt sekä nykyisen solmun N että entisen isovanhemman G vanhempi . Tiedetään, että G on musta, koska sen entinen lapsi P ei muuten voisi olla punainen (rikkomatta ominaisuutta 4). Sitten P :n ja G :n värit vaihtuvat ja tämän seurauksena puu täyttää ominaisuuden 4 (mikä tahansa punaisen solmun molemmat lapset ovat mustia). Ominaisuus 5 (Kaikki polut mistä tahansa solmusta lehtisolmuihin sisältävät saman määrän mustia solmuja) pysyy myös totta, koska kaikki polut, jotka kulkevat minkä tahansa näistä kolmesta solmusta, kulkivat aiemmin G :n kautta , joten nyt ne kaikki kulkevat P :n kautta . Kussakin tapauksessa näistä kolmesta solmusta vain yksi on musta. |
Kun normaalista binäärihakupuusta poistetaan solmu, jossa on kaksi ei-lehteä lasta, etsitään joko sen vasemmanpuoleisesta alipuusta suurin elementti tai oikeasta alipuusta pienin elementti ja siirretään sen arvo poistettavaan solmuun. Poistamme sitten solmun, josta kopioimme arvon. Arvon kopioiminen solmusta toiseen ei riko punamustan puun ominaisuuksia, koska puun rakenne ja solmujen värit eivät muutu. On syytä huomata, että poistettavassa uudessa solmussa ei voi olla kahta ei-lehtiä olevaa lapsisolmua kerralla, muuten se ei ole suurin/pienin elementti. Siten käy ilmi, että tapaus poistaa solmu, jolla on kaksi ei-lehteä alisolmua, pelkistyy tapaukseksi, jossa poistetaan solmu, joka sisältää enintään yhden ei-lehtisen alisolmun. Siksi jatkokuvauksessa lähdetään olettamuksesta, että poistettavalla solmulla on enintään yksi ei-lehtinen lapsi.
Käytämme merkintää M poistettavalle solmulle; merkitsemme C :llä M : n jälkeläistä , jota kutsumme myös yksinkertaisesti "sen jälkeläiseksi". Jos M :llä on ei-lehtinen lapsi, ota se C :ksi . Muuten C :lle otamme minkä tahansa lehtien jälkeläisistä.
Jos M on punainen solmu, korvaa se lapsillamme C , jonka määritelmän mukaan on oltava musta. (Tämä voi tapahtua vain, kun M :llä on kaksi lehtiä, koska jos punaisella solmulla M on musta ei-lehtilapsi toisella puolella ja lehtilapsi toisella puolella, niin mustien solmujen määrä molemmilla puolilla on erilainen, jolloin puusta tulee virheellinen. punainen-musta puu ominaisuuden 5 rikkomisen vuoksi.) Kaikki poistettavan solmun läpi kulkevat polut sisältävät yksinkertaisesti yhden punaisen solmun vähemmän, poistettavan solmun ylä- ja alaosan on oltava mustia, joten Kiinteistö 3 ("Kaikki lehdet ovat mustia") ja ominaisuus 4 ("Punaisen solmun molemmat lapset ovat mustia") ovat edelleen voimassa.
Toinen yksinkertainen tapaus on, kun M on musta ja C on punainen. Pelkästään mustan solmun poistaminen rikkoisi ominaisuutta 4 ("Punaisen solmun molemmat lapset ovat mustia") ja ominaisuutta 5 ("Jokainen yksinkertainen polku tietystä solmusta mihin tahansa lehtisolmuun sisältää saman määrän mustia solmuja"), mutta jos me värjätä C mustaksi, molemmat ominaisuudet säilyvät.
Vaikea tapaus on, kun sekä M että C ovat mustia. (Tämä voi tapahtua vain, kun musta solmu, jossa on kaksi lehtilapsia, poistetaan, koska jos mustassa solmussa M on musta ei-lehtilapsi toisella puolella ja lehtilapsi toisella, niin mustien solmujen lukumäärä molemmilla puolilla on erilainen ja puusta tulee virheellinen punamusta puu, koska ominaisuus 5 on rikottu.) Aloitamme korvaamalla solmun M sen lapsilla C . Kutsumme tätä jälkeläistä (sen uudessa asemassa) N :ksi ja sen "veljeksi" (sen uuden esi-isän toiseksi jälkeläiseksi) - S. (Aiemmin S oli M :n "veli" .) Alla olevissa kuvissa käytämme myös merkintää P N :n uudelle esi- isälle ( M :n vanha esi-isä ), S L :n S :n vasemmalle lapselle , ja S R S :n oikealle lapselle ( S ei voi olla lehtisolmu , koska jos N oletuksenamme on musta, niin N:n sisältävä alipuu P on korkeudeltaan kaksi musta ja siksi P :n toisen alipuun, joka sisältää S :n, täytyy myös olla musta korkeudeltaan kaksi, mikä ei voi olla tilanne, kun S on lehti) .
Huomautus : Joissakin tapauksissa muutamme solmujen rooleja ja nimityksiä, mutta jokaisessa tapauksessa mikä tahansa nimitys tarkoittaa edelleen samaa solmua kuin tapauksen alussa. Kuvassa näkyvät värit ovat joko sattumanvaraisia tai saatu muista oletuksista. Valkoinen tarkoittaa tuntematonta väriä (joko punaista tai mustaa).Etsimme "veljeä" käyttämällä tätä toimintoa:
rakennesolmu * _ sisarus ( rakennesolmu * n ) _ { if ( n == n -> vanhempi -> vasen ) return n -> vanhempi -> oikea ; muu paluu n -> vanhempi -> vasen ; } Huomautus : Jotta puu pysyisi oikein määriteltynä, jokaisen lehden on pysyttävä lehdenä kaikkien muutosten jälkeen (joten sillä ei ole lapsia). Jos poistettavalla solmulla on ei-lehtinen ali N , on helppo nähdä, että ominaisuus on voimassa. Toisaalta, jos N on lehti, niin, kuten kuvista tai koodista näkyy, myös ominaisuus pätee.Voimme suorittaa yllä olevat vaiheet käyttämällä seuraavaa koodia, jossa funktio replace_nodekorvaa puun childsolmun . nMukavuussyistä tämän osan koodi olettaa, että tyhjät lehdet edustavat todellisia solmuobjekteja, eivät NULL:ia (lisäyskoodin tulisi toimia samalla esityksellä).
void korvaa_solmu ( solmu * n , solmu * lapsi ) { lapsi -> vanhempi = n -> vanhempi ; if ( n == n -> vanhempi -> vasen ) { n -> vanhempi -> vasen = lapsi ; } muu { n -> vanhempi -> oikeus = lapsi ; } } mitätön delete_one_child ( struct solmu * n ) { /* * Ehto: n:llä on enintään yksi nollasta poikkeava lapsi. */ struct solmu * lapsi = is_leaf ( n -> oikea ) ? n -> vasen : n -> oikea ; korvaa_solmu ( n , lapsi ); if ( n -> väri == MUSTA ) { jos ( lapsi -> väri == PUNAINEN ) lapsi -> väri = MUSTA ; muu delete_case1 ( lapsi ); } vapaa ( n ); } Huomautus : Jos N on nollalehti, emmekä halua esittää nollalehtiä todellisina objekteina, voimme muokata algoritmia kutsumalla ensin delete_case1() sen yläpuolella (solmu n, jonka poistimme yllä olevasta koodista) ja poistamalla sen jälkeen että. Voimme tehdä tämän, koska isä on musta ja siksi käyttäytyy kuin tyhjä lehti (ja sitä kutsutaan joskus "haamulehdeksi"). Voimme poistaa sen turvallisesti, koska se npysyy lehtinä kaikkien yllä olevien toimenpiteiden jälkeen.Jos N ja sen nykyinen isä ovat mustia, isän poistaminen aiheuttaa N :n läpi kulkeville poluille yhden mustan solmun vähemmän kuin poluilla, jotka eivät kulje sen läpi. Koska tämä rikkoo ominaisuutta 5 (kaikki polut mistä tahansa solmusta sen lehtisolmuihin sisältävät saman määrän mustia solmuja), puu on tasapainotettava uudelleen. On useita harkitsevia tapauksia:
Tapaus 1: N on uusi juuri. Tässä tapauksessa kaikki on tehty. Olemme poistaneet jokaiselta polulta yhden mustan solmun ja uusi juuri on musta solmu, joten ominaisuudet säilyvät.
mitätön delete_case1 ( struct solmu * n ) { if ( n -> vanhempi != NULL ) poista_tapaus2 ( n ); } Huomaa : Tapauksissa 2, 5 ja 6 oletetaan, että N on esi-isänsä P vasen lapsi . Jos kyseessä on oikea lapsi, vasen ja oikea on vaihdettava kaikissa kolmessa tapauksessa. Jälleen koodiesimerkit ottavat tämän huomioon.Tapaus 2: S on punainen. Tässä tapauksessa vaihdamme P :n ja S :n värit ja teemme sitten kierron vasemmalle P :n ympäri , jolloin S on N :n isovanhempi . Huomaa, että P :n on oltava musta, jos siinä on punainen lapsi. Tuloksena saatavassa alipuussa on vielä yksi musta solmu vähemmän, joten emme ole vielä valmiit siihen. Nyt N :llä on musta sisarus ja punainen isä, joten voimme siirtyä vaiheisiin 4, 5 tai 6. (Hänen uusi sisaruksensa on musta, koska hän oli punaisen S :n jälkeläinen .)
Seuraavassa S tarkoittaa uutta veljeä N. |
Tapaus 3: P :n , S :n ja S:n lapset ovat mustia. Tässä tapauksessa värjäämme vain S - punaisen. Tämän seurauksena kaikilla poluilla S :n läpi mutta ei N :n kautta on yksi musta solmu vähemmän. Koska N :n isän poistaminen aiheuttaa sen, että kaikki N :n kautta kulkevat polut sisältävät yhden mustan solmun vähemmän, tällaiset toimet tasoittavat tasapainoa. Kuitenkin kaikki P :n kautta kulkevat polut sisältävät nyt yhden mustan solmun vähemmän kuin polut, jotka eivät kulje P :n läpi , joten ominaisuus 5 (kaikki polut mistä tahansa kärjestä sen lehtisolmuihin sisältävät saman määrän mustia solmuja) on edelleen rikki. Korjataksemme tämän soveltamalla tasapainotusmenettelyä P :hen tapauksesta 1 alkaen. |
Tapaus 4: S ja hänen lapsensa ovat mustia, mutta P on punainen. Tässä tapauksessa muutamme vain S :n ja P :n värejä . Tämä ei vaikuta mustien solmujen määrään reiteillä S :n läpi , mutta lisää yhden mustien solmujen määrään reiteillä N :n kautta , mikä palauttaa poistetun mustan solmun vaikutuksen. |
Tapaus 5: S on musta, S :n vasen lapsi on punainen, S :n oikea lapsi on musta ja N on isänsä vasen lapsi. Tässä tapauksessa käännämme puuta oikealle S :n ympäri . Siten S : n vasemmasta lapsesta tulee sen isä ja N :n uusi veli . Sen jälkeen vaihdamme S :n ja hänen uuden isänsä värit. Kaikissa poluissa on edelleen sama määrä mustia solmuja, mutta nyt N :llä on musta sisarus, jolla on punainen oikea lapsi, ja siirrytään tapaukseen 6. N tai sen isä eivät vaikuta tähän transformaatioon. (Tapauksessa 6 merkitsemme S :llä N :n uutta veljeä .) |
Tapaus 6: S on musta, S : n oikea lapsi on punainen ja N on isänsä P vasen lapsi . Tässä tapauksessa käännämme puuta vasemmalle P :n ympäri , minkä jälkeen S :stä tulee P : n ja sen oikean lapsen vanhempi. Seuraavaksi vaihdamme P:n ja S:n värit ( P saa S : n värin , S saa P :n värin ) ja S : n oikeasta lapsesta tulee musta. Alipuulla on edelleen sama juuriväri, joten ominaisuuksia 4 (kunkin punaisen solmun molemmat lapset ovat mustia) ja 5 (kaikki polut mistä tahansa kärjestä sen lehtisolmuihin sisältävät saman määrän mustia solmuja) ei rikota. Kuitenkin N :llä on nyt ylimääräinen musta esi-isä: joko P :stä tuli musta tai se oli musta ja S lisättiin mustaksi isovanhemmaksi. Siten N :n kautta kulkevat reitit kulkevat yhden mustan lisäsolmun läpi. Sillä välin, jos polku ei kulje N :n läpi, on kaksi mahdollista vaihtoehtoa:
Joka tapauksessa mustien solmujen määrä näillä poluilla ei muutu. Siksi olemme palauttaneet ominaisuudet 4 (kunkin punaisen solmun molemmat lapset ovat mustia) ja 5 (kaikki polut mistä tahansa kärjestä sen lehtisolmuihin sisältävät saman määrän mustia solmuja). Kaavion valkoinen solmu voi olla joko punainen tai musta, mutta sen tulee osoittaa samaa väriä sekä muunnoksen alussa että lopussa. |
Kaikki rekursiiviset funktiokutsut pyrstoidaan ja muunnetaan silmukoiksi, joten algoritmi vaatii O(1)-muistin . Yllä olevassa algoritmissa kaikki tapaukset yhdistetään vuorotellen, paitsi tapaus 3, jossa voi tapahtua paluu tapaukseen 1, mikä koskee solmun esi-isä: tämä on ainoa tapaus, jossa peräkkäinen toteutus on tehokas silmukka (yhden jälkeen kierto tapauksessa 3).
Häntärekursiota ei myöskään esiinny koskaan lapsisolmuissa, joten häntärekursiosilmukka voi siirtyä vain lapsisolmuista heidän peräkkäisiin vanhempiinsa. Tapaukseen 1 ei tule enempää kuin O(log n ) edestakaista matkaa (jossa n on solmujen kokonaismäärä puussa ennen poistamista). Jos kierto tapahtuu tapauksessa 2 (ainoa mahdollinen tapausten 1-3 syklissä), niin solmun N isä muuttuu punaiseksi kierron jälkeen ja poistumme syklistä. Siten tämän jakson aikana ei suoriteta enempää kuin yksi kierto. Silmukasta poistumisen jälkeen tulee enintään kaksi lisäkiertoa. Yleensä puussa ei ole enempää kuin kolme kiertoa.
Olkoon puun korkeus h, pisteiden vähimmäismäärä N. Sitten:
Siksi samalla lehtimäärällä punamusta puu voi olla korkeampi kuin AVL-puu, mutta enintään kertoimella 1. [5]
Koska punamusta puu on pahimmassa tapauksessa korkeampi, haku siinä on hitaampaa, mutta aikahäviö ei ylitä 39%.
Asennus vaatii enintään 2 kierrosta molemmissa puutyypeissä. Punamustan puun suuremman korkeuden vuoksi lisääminen voi kuitenkin kestää kauemmin.
Punamustasta puusta poistaminen vaatii jopa 3 kiertoa, AVL-puussa se voi vaatia useita kierroksia puun syvyyteen (juureen asti). Siksi poistaminen punamustasta puusta on nopeampaa kuin poistaminen AVL-puusta. Kuitenkin testit osoittavat, että AVL-puut ovat nopeampia kuin puna-mustat puut kaikissa operaatioissa [6] [7] , viimeisimmän testin kirjoittaja ehdottaa, että punamustat puut voivat olla tehokkaampia suurella muistimäärällä [8] .
Jokaisen solmun AVL-puu tallentaa korkeuseron (kokonaisluku -1 - +1, koodaukseen tarvitaan 2 bittiä). Punamusta puu jokaisessa solmussa tallentaa värin (1 bitti). Näin ollen punamusta puu voi olla taloudellisempi. (Totta, kun otetaan huomioon, että nykyaikaisissa tietokonejärjestelmissä muisti on varattu tavujen kerrannaisina, puut ovat täsmälleen samat)
Käytännössä kuitenkin molemmissa puutyypeissä käytetään kokonaislukuja, koska bittien kanssa työskentely vaatii prosessorin lisälaskelmia (yksi assembler-käsky ja %al 0x10000000). On kuitenkin olemassa punamusta-puun toteutuksia, jotka tallentavat väriarvon bitteinä. Esimerkki on Boost Multiindex . Värin bitin tallentamisen tarkoitus on vähentää puna-mustan puun muistin kulutusta ( Ordered indexes node compression ). Tämän toteutuksen väribittiä ei tallenneta erilliseen muuttujaan, vaan johonkin puun solmuosoittimista, jolloin se muuttuu leimatuksi osoittimeksi .
Punamustan puun, joka sisältää n sisäistä solmua, korkeus on .
Nimitykset:
Lemma: Solmuun juurtuneella alipuulla on vähintään sisäiset solmut.
Lemman todistus (korkeuden induktiolla):
Induktion perusta: .
Jos alipuun korkeus on nolla, sen on oltava nolla , joten .
Niin:
Induktiovaihe: olkoon solmu sellainen, että alipuussa on myös vähintään sisäisiä solmuja.
Osoittakaamme, että silloin , jolle , on ainakin sisäiset solmut.
Koska sillä on , se on sisäinen solmu. Sellaisenaan sillä on kaksi lasta, jotka molemmat ovat mustapituisia , joko (riippuen siitä, onko se punainen vai musta).
Induktiohypoteesin mukaan jokaisella jälkeläisellä on vähintään sisäiset solmut, ja siksi sillä on vähintään
sisäiset solmut.
Tämän lemman avulla voimme osoittaa, että puulla on logaritminen korkeus. Koska vähintään puolet minkä tahansa polun solmuista juuresta lehtiin on mustia (punamustan puun ominaisuus 4), juuren musta korkeus on vähintään . Lemman mukaan meillä on:
Juuren korkeus on siis .
Puu (tietorakenne) | |
---|---|
Binääripuut | |
Itsetasapainottavat binaaripuut |
|
B-puut | |
etuliite puita |
|
Avaruuden binaarinen osiointi | |
Ei-binääripuut |
|
Avaruuden hajottaminen |
|
Muut puut |
|
Algoritmit |