Binary Tre Rotasjon

stemmer
3

Jeg jobber med å implementere en AVL Søk treet. Så langt jeg er ferdig koding del og jeg har begynt å teste den for feil. Jeg fant ut at mine node rotasjon metoder er avlyttet og for Guds skyld jeg kan ikke forstå hva som er problemet.

Algoritmen fungerer som det skal på papiret, men når utført på en maskin det godt ... lekker tre noder.

Dette er den metode som benyttes for å rotere en node til venstre: http://pastebin.com/mPHj29Af

bool avl_search_tree::avl_tree_node::rotate_left()
{
    if (_right_child != NULL) {
        avl_tree_node *new_root = _right_child;
 
        if (_parent != NULL) {
            if (_parent->_left_child == this) {
                _parent->_left_child = new_root;
            } else {
                _parent->_right_child = new_root;
            }
        }
 
        new_root->_parent = _parent;
        _parent = new_root;
 
        _right_child = new_root->_left_child;
        new_root->_left_child = this;
 
        if (_right_child != NULL) {
            _right_child->_parent = this;
        }
 
        //update heights
        update_height();
        new_root->update_height();
 
        return true;
    }
 
    return false;
}

I min innsetting metoden kommen jeg AVL balansere del og i stedet jeg prøver bare å rotere nyinnsatte noden til venstre. Resultatet for å sette inn hele tall i stigende rekkefølge: min treet bare inneholder den opprinnelige rot (første noden er satt inn) og alle andre noder er lekket.

Alle hjelpe med å identifisere problemet er høyt verdsatt som jeg begynner å bli gal.

For ordens skyld: hvis jeg ikke bruker noen rotasjoner treet ikke vil lekke noder og det fungerer som en vanlig ubalansert binært søketre (for innsetting og oppslag).

Edit: På grunn av AJG85 kommentar vil jeg legge observasjonene:

Jeg har lagt printf 'sjekker' for å destructor metoden for avl_search_tree :: avl_tree_node som vil skrive ut nøkkelverdien (i mitt tilfelle 32 bits heltall) før opprydding og til innsatsen metoden i avl_search_tree som skal skrive ut nøkkelen bare satt inn.

Så i programmets Entrypoint jeg tildele en avl_search_tree på haugen og legge nøklene til det i stigende rekkefølge og deretter slette den.

Med AVL Balancing aktivert får jeg følgende resultat i terminalen:

bool avl_search_tree::insert(const int&) : 1
bool avl_search_tree::insert(const int&) : 2
bool avl_search_tree::insert(const int&) : 3
bool avl_search_tree::insert(const int&) : 4
bool avl_search_tree::insert(const int&) : 5
bool avl_search_tree::insert(const int&) : 6
bool avl_search_tree::insert(const int&) : 7
bool avl_search_tree::insert(const int&) : 8
avl_search_tree::avl_tree_node::~avl_tree_node() : 1

Hvilket betyr thatall innsett var vellykket, men bare roten har blitt slettet.

Med AVL Avbalanseringen kommentert ut det fungerer som en vanlig binært søketre. Terminalen utgang er:

bool avl_search_tree::insert(const int&) : 1
bool avl_search_tree::insert(const int&) : 2
bool avl_search_tree::insert(const int&) : 3
bool avl_search_tree::insert(const int&) : 4
bool avl_search_tree::insert(const int&) : 5
bool avl_search_tree::insert(const int&) : 6
bool avl_search_tree::insert(const int&) : 7
bool avl_search_tree::insert(const int&) : 8
avl_search_tree::avl_tree_node::~avl_tree_node() : 1
avl_search_tree::avl_tree_node::~avl_tree_node() : 2
avl_search_tree::avl_tree_node::~avl_tree_node() : 3
avl_search_tree::avl_tree_node::~avl_tree_node() : 4
avl_search_tree::avl_tree_node::~avl_tree_node() : 5
avl_search_tree::avl_tree_node::~avl_tree_node() : 6
avl_search_tree::avl_tree_node::~avl_tree_node() : 7
avl_search_tree::avl_tree_node::~avl_tree_node() : 8

Hvilket betyr at alt er skikkelig rengjort.

Nå ... hvordan har jeg kommet til den konklusjon at rotasjons metoder er problemene? Under kommen AVL balansering subrutine jeg lagt til en linje som roterer hver nyinnsatte node til venstre. Resultatet? Det samme som om AVL Balancing subrutine ble aktivert.

Og om update_height () -metoden, betyr det ikke endrer treets struktur på noen måte.

Jeg håper dette vil avklare det.

Edit 2:

For å klargjøre noen flere ting, er hans hvordan avl_tree_node destructor er gjennomført:

avl_search_tree::avl_tree_node::~avl_tree_node()
{
    printf(%s : %d\n, __PRETTY_FUNCTION__, *_key);

    if (_left_child != NULL) {
        delete _left_child;
    }

    if (_right_child != NULL) {
        delete _right_child;
    }

    if (_key != NULL) {
        delete _key;
    }
}

_left_child og _right_child er pekere til avl_tree_node gjenstander tildelt på haugen.

Edit 3:

Takket være AGJ85 sin andre kommentaren jeg fant problemet. I mine roter metoder glemte jeg at jeg faktisk må oppdatere treets rot peker til den nye rot når roten ble flyttet.

I utgangspunktet treets rot ble alltid peker til den første noden innsatt og uten å oppdatere pekeren når det er nødvendig, ville mine rotere metoder lekke den nye treets rot som faktisk ble konfigurert til høyre. :)

Takk AGJ85!

Publisert på 02/08/2011 klokken 17:19
kilden bruker
På andre språk...                            


3 svar

stemmer
2

EDIT - Damn - Jeg så ikke at problemet er allerede løst (svar på spørsmålet). Likevel, kanskje det er noen ikke-svar tips i denne verdt berging.

Jeg har ikke sjekket grundig, men jeg tror du kommer galt på denne linjen ...

_right_child = new_root->_left_child;

og at problemet er at du kanskje allerede har overskrevet new_root->_left_childi tråd ...

_parent->_left_child = new_root;

Det jeg synes du skal gjøre er, i starten, har en blokk med lokale definisjoner som ...

avl_tree_node *orig_parent      = _parent;
avl_tree_node *orig_this        = this;
avl_tree_node *orig_left_child  = _left_child;
avl_tree_node *orig_right_child = _right_child;

Deretter bruker de orig_lokale variabler som kilder for senere oppdrag. Dette sparer en viss mengde for å bekymre seg om data som strømmer gjennom de forskjellige pekere under rotasjonen. Den Optimizer skal kvitte seg med noen overflødig arbeid verdt å bekymre seg i dette, og det er ikke mye av det allikevel.

Et par ekstra poeng ...

Først, C ++ (og C) standarder reserve identifikatorer med ledende understrek, og med dobbeltstrek. Det er hevdet at du kan få overraskende interaksjoner med standard og kompilatoren levert bibliotekene hvis du ikke respekterer det - jeg antar at det måtte være makro-relaterte for medlems identifikatorer, skjønt. Løpende strek er OK - jeg har en tendens til å bruke dem etter inkludere vakter.

En vanlig konvensjon for medlemsvariablene er å legge til en ledende meller m_. Enda mer vanlig, sannsynligvis, ikke er å ha noen spesiell prefiks eller suffiks i det hele tatt.

Dernest, du kan (eller kanskje ikke) synes det er lettere å implementere AVL trær som ikke har foreldre linker lagret i nodene. Jeg har ikke implementert AVL trær ennå selv, men jeg gjorde implementere rød-svart trær gang. En rekke algoritmer må inkludere en rekursiv søk som første skritt - du kan ikke bare gjøre en standard søk som husker funnet noden men forkaster ruten ned til den noden. Imidlertid er rekursiv implementeringen ikke så ille, og det er færre pekere til å sjonglere.

Endelig et generelt tips - prøver å "tørr kjøre" en algoritme som dette kan lett reise deg opp med mindre du strengt arbeide gjennom det steg for steg, og sjekke alle kilder til informasjon som er relevant (har jeg allerede endret dette?) På hvert steg. Det er veldig lett å komme inn i vanen med å hoppe over noen av detaljene for hastighet. En nyttig maskin-assistert tørr kjøre er å kjøre koden steg-for-steg i en debugger, og se om resultatene på hvert trinn er enig med papirtørrkjøring.

EDIT - en mer oppmerksom - Jeg vil ikke kalle dette et tips fordi jeg er ikke sikker på i denne sammenheng. Jeg pleier å implementere datastruktur noder med enkle structs - ingen data skjule, få om noen medlemsfunksjoner. Mesteparten av koden holdes atskilt fra datastrukturen, ofte i et "verktøy" klasse. Jeg vet dette bryter den gamle "formen trekker seg" OOP prinsippet, men IMO det fungerer bedre i praksis.

Svarte 02/08/2011 kl. 19:34
kilden bruker

stemmer
3

Takket være AGJ85 sin andre kommentaren jeg fant problemet. I mine roter metoder glemte jeg at jeg faktisk må oppdatere treets rot peker til den nye rot når roten ble flyttet.

I utgangspunktet treets rot ble alltid peker til den første noden innsatt og uten å oppdatere pekeren når det er nødvendig, ville mine rotere metoder lekke den nye treets rot som faktisk ble konfigurert til høyre. :)

Svarte 03/08/2011 kl. 09:03
kilden bruker

stemmer
1

Jeg ser du har funnet feilen du leter etter i koden din. (Som du sier, var du ikke oppdatere trerot pekeren til den nye rot når roten endret. Det er en vanlig paradigme for listen og tre Sett / Slett metoder for å returnere en peker til leder av listen eller roten av treet, og hvis du huske at paradigmet vil ikke gjøre den feilen igjen.)

På et høyere nivå av visningen, den teknikk som jeg har anvendt for å unngå problemer med AVL treet eller rød-svart treet kode er å i stedet benytte en AA treet , som har lignende ytelse til dem, ved anvendelse av O (n) plass og O (log n) tid for sette inn, slette og søk. Men AA trær er betydelig enklere å kode.

Svarte 04/08/2011 kl. 15:55
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more