Stackoverflow unntak når traversering BST

stemmer
4

Jeg har implementere en link-basert BST (binært søketre) i C ++ for en av mine oppdrag. Jeg har skrevet min hele klassen og alt fungerer bra, men min oppgave ber meg om å plotte run-tider for:

a.  A sorted list of 50000, 75000, and 100000 items
b.  A random list of 50000, 75000, and 100000 items

Det er greit, jeg kan sette inn tallene, men den ber meg også til å ringe FindHeight()og CountLeaves()metoder på treet. Mitt problem er at jeg har gjennomført de to funksjonene du bruker recursion. Siden jeg har en så stor liste med tall jeg får å få et stackoverflowunntak.

Her er min klasse definisjon:

template <class TItem>
class BinarySearchTree
{
public:
    struct BinarySearchTreeNode
    {
    public:
        TItem Data;
        BinarySearchTreeNode* LeftChild;
        BinarySearchTreeNode* RightChild;
    };

    BinarySearchTreeNode* RootNode;

    BinarySearchTree();
    ~BinarySearchTree();

    void InsertItem(TItem);

    void PrintTree();
    void PrintTree(BinarySearchTreeNode*);

    void DeleteTree();
    void DeleteTree(BinarySearchTreeNode*&);

    int CountLeaves();
    int CountLeaves(BinarySearchTreeNode*);

    int FindHeight();
    int FindHeight(BinarySearchTreeNode*);

    int SingleParents();
    int SingleParents(BinarySearchTreeNode*);

    TItem FindMin();
    TItem FindMin(BinarySearchTreeNode*);

    TItem FindMax();
    TItem FindMax(BinarySearchTreeNode*);
};

FindHeight () Innføring

template <class TItem>
int BinarySearchTree<TItem>::FindHeight()
{
    return FindHeight(RootNode);
}

template <class TItem>
int BinarySearchTree<TItem>::FindHeight(BinarySearchTreeNode* Node)
{
    if(Node == NULL)
        return 0;

    return 1 + max(FindHeight(Node->LeftChild), FindHeight(Node->RightChild));
}

CountLeaves () gjennomføring

template <class TItem>
int BinarySearchTree<TItem>::CountLeaves()
{
    return CountLeaves(RootNode);
}

template <class TItem>
int BinarySearchTree<TItem>::CountLeaves(BinarySearchTreeNode* Node)
{
    if(Node == NULL)
        return 0;
    else if(Node->LeftChild == NULL && Node->RightChild == NULL)
        return 1;
    else
        return CountLeaves(Node->LeftChild) + CountLeaves(Node->RightChild);
}

Jeg prøvde å tenke på hvordan jeg kan implementere de to metodene uten rekursjon, men jeg er helt stabbet. Alle som har noen ideer?

Publisert på 09/11/2011 klokken 23:52
kilden bruker
På andre språk...                            


5 svar

stemmer
1

For å telle bladene uten rekursjon, bruker begrepet en iterator som STL bruker for RB-tree underliggende std::setog std::map... Lag en begin()og end()funksjon for deg tre som identifiserer de bestilte første og siste node (i dette tilfellet venstre -De fleste node og lengst til høyre node). Deretter oppretter du en funksjon som heter

BinarySearchTreeNode* increment(const BinarySearchTreeNode* current_node)

at for en gitt current_node, vil returnere en peker til den neste node i treet. Husk for denne implementeringen til arbeid, vil du trenger en ekstra parentpeker i nodetypen til hjelp i iterasjonen prosessen.

Din algoritme for increment()ville se noe sånt som følgende:

  1. Sjekk for å se om det er en høyre barn til gjeldende node.
  2. Hvis det er en høyre barn, bruke en while-løkke for å finne lengst til venstre node av denne rett treet. Dette vil være den "neste" node. Ellers går du til trinn # 3.
  3. Hvis det ikke er rett-barn på den aktuelle noden, så sjekk for å se om den aktuelle noden er venstre barn av sin overordnede noden.
  4. Hvis trinn # 3 er sant, så "neste" node er foreldrenoden, slik at du kan stoppe på dette punktet, ellers gå til neste trinn.
  5. Dersom steg # 3 var falsk, da den nåværende node er høyre barn av foreldre. Dermed må du holde flytte opp til neste foreldrenoden ved hjelp av en stund loop til du kommer over en node som er en venstre-barn av den overordnede noden. Forelder til denne venstre-barn-node vil da være "neste" node, og du kan stoppe.
  6. Til slutt, hvis steg # 5 tar deg tilbake til roten, da den nåværende node er den siste node i treet, og iterator har nådd slutten av treet.

Til slutt trenger du en bool leaf(const BinarySearchTreeNode* current_node)funksjon som vil teste om en gitt node er en bladnode. Dermed teller funksjonen kan bare gjenta om treet og finne alle bladnoder, tilbake en endelig opptelling når den er ferdig.

Hvis du ønsker å måle maksimal dybde på en ubalansert tre uten rekursjon, vil du, i treets insert()funksjon, trenger å holde styr på den dybden som en node ble satt inn. Dette kan rett og slett være en variabel i nodetype som er satt når noden er satt inn i treet. Du kan deretter iterere gjennom de tre, og finne den maksimale dybden av et blad-node.

BTW, er kompleksiteten i denne metoden dessverre kommer til å være O (N) ... ikke på langt nær så hyggelig som O (log N).

Svarte 10/11/2011 kl. 00:01
kilden bruker

stemmer
3

Rekursjon på et tre med 100.000 noder bør ikke være et problem hvis det er balansert. Dybden vil bare være kanskje 17, som ikke ville bruke meget stabel i de implementeringer som er vist. (log2(100,000) = 16.61). Så det virker som kanskje koden som bygger treet er ikke å balansere det riktig.

Svarte 10/11/2011 kl. 00:02
kilden bruker

stemmer
1

Kan være du må beregne dette mens du gjør innsatsen. Oppbevar høyder av noder, det vil si legge til et heltall felt som høyde i Node objektet. har også tellere høyde og blader for treet. Når du setter inn en node, hvis foreldrene er (var) et blad, blad teller doesnt endring, men hvis ikke, øke blad teller med 1. Også høyden på den nye noden er foreldrenes høyde + 1, dermed hvis det er større enn dagens høyde av treet, deretter oppdatere den. Dens en lekser, så jeg vil ikke hjelpe med selve koden

Svarte 10/11/2011 kl. 00:05
kilden bruker

stemmer
2

Jeg fant denne siden veldig opplysende fordi den snakker om mekanikken i å konvertere en funksjon som bruker rekursjon til en som bruker iterasjon.

Den har eksempler som viser kode også.

Svarte 10/11/2011 kl. 00:06
kilden bruker

stemmer
1

Balansere treet og til. Hvis treet blir Stackoverflow på FindHeight (), betyr at treet er helt ubalansert. Dersom treet er balansert skal det bare ha en dybde på omtrent 20 noder for 100000 elementene.

Den enkleste (men ganske treg) måte å re-balansere ubalansert binært tre er å tildele en rekke TItemstore nok til å holde alle data i treet, setter alle dine data inn i det i sortert rekkefølge, og slette alle nodene . Deretter gjenoppbygge treet fra matrisen rekursivt. Roten er noden i midten. root->lefter midt i venstre halvdel, root->righter midt på høyre halvdel. Gjenta rekursivt. Dette er den enkleste måten å balansere, men det er slowish og tar mye minne midlertidig. På den annen side, trenger du bare å gjøre dette når du oppdager at treet er svært ubalansert, (dybde på innsatsen er mer enn 100).

Den andre (bedre) alternativ er å balansere under innsatser. Den mest intuitive måten å gjøre dette på er å holde styr på hvor mange noder er under gjeldende node. Hvis retten barn har mer enn dobbelt så mange "barn" noder som venstre barn, "roter" venstre. Og vice versa. Det er instrcutions om hvordan du gjør treet roterer over hele internett. Dette gjør innsatser litt tregere, men da du ikke har sporadiske massive boder som det første alternativet skaper. På den annen side, må du hele tiden oppdatere alle "barn" teller som du gjør de roterer, som ikke er trivielt.

Svarte 10/11/2011 kl. 00:08
kilden bruker

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