excepție StackOverflow atunci când traversează BST

voturi
4

Am să pună în aplicare o BST bazată pe link-(arbore binar de căutare) în C ++ pentru unul din misiunea mea. Am scris toată clasa mea și totul funcționează bine, dar misiunea mea îmi cere să complot run-time pentru:

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

Asta e bine, eu pot insera numerele , dar , de asemenea , mi cere pentru a apela FindHeight()și CountLeaves()metodele de pe copac. Problema mea este că am pus în aplicare cele două funcții folosind recursion. Din moment ce am o astfel de listă mare de numere îmi furnizează obtinerea o stackoverflowexcepție.

Iată definiția mea de clasă:

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 () de punere în aplicare

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 () punerea în aplicare

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);
}

Am încercat să mă gândesc cum pot pune în aplicare cele două metode fără recursie, dar eu sunt complet stumped. Oricine are vreo idee?

Întrebat 10/11/2011 la 00:52
sursa de către utilizator
În alte limbi...                            


5 răspunsuri

voturi
1

Pentru a număra frunzele fără recursie, utilizează conceptul de un iterator ca STL folosește pentru RB-copac care stau la baza std::setși std::map... Creează begin()și end()funcția de copac vă că indentifică primul și ultimul nod ordonat (în acest caz , în stânga nod -most și apoi cel mai din dreapta nod). Apoi , creați o funcție numită

BinarySearchTreeNode* increment(const BinarySearchTreeNode* current_node)

că , pentru o anumită current_node, se va întoarce un pointer la următorul nod din arbore. Păstrați în minte pentru această punere în aplicare la locul de muncă, veți avea nevoie de un plus parentindicator în dvs. de nodetip pentru a ajuta la procesul de repetare.

Algoritmul dvs. de increment()ar arata ceva de genul următoarele:

  1. Verificați pentru a vedea dacă există un copil dreptul la nodul curent.
  2. Dacă există un copil-dreapta, utilizați un timp-bucla pentru a găsi nodul cel mai din stânga acelui subarborelui drept. Aceasta va fi „următoarea“ nod. În caz contrar, mergeți la pasul # 3.
  3. Dacă nu există nici un drept copil pe nodul curent, apoi verificați pentru a vedea dacă nodul curent este stânga-copil al nodului părinte.
  4. Dacă pasul # 3 este adevărat, atunci „următor“ nod este nodul părinte, astfel încât să puteți opri la acest punct, în caz contrar du-te la pasul următor.
  5. În cazul în care pasul # 3 a fost falsă, atunci nodul curent este dreapta-copil al părintelui. Astfel, va trebui să păstreze în mișcare până la următorul nod părinte utilizând o buclă în timp până când ajunge peste un nod care este un copil-stânga al nodului părinte. Părintele acestui nod stânga-copil va fi apoi „urmatorul“ nod, și vă puteți opri.
  6. În cele din urmă, în cazul în care etapa # 5 revine la rădăcină, atunci nodul curent este ultimul nod din copac, iar iteratorul a ajuns la capătul arborelui.

În cele din urmă veți avea nevoie de o bool leaf(const BinarySearchTreeNode* current_node)funcție care va testa dacă un anumit nod este un nod frunză. Astfel , funcția pe care pur și simplu contra se poate repeta , deși copac și pentru a găsi toate nodurile frunze, revenind un număr de finală după ce a făcut.

Dacă doriți să măsoare adâncimea maximă a unui arbore dezechilibrat fără recursie, va, în arborele lui insert()funcție, trebuie să țină evidența de adâncimea pe care un nod a fost inserat la. Acest lucru poate fi pur și simplu o variabilă în dvs. de nodetip , care este setat atunci când nodul este inserat în copac. Puteți itera apoi prin cele trei, și pentru a găsi adâncimea maximă a unei frunze de -nod.

BTW, complexitatea acestei metode este, din păcate, va fi O (N) ... nici pe departe la fel de frumos ca și O (log N).

Publicat 10/11/2011 la 01:01
sursa de către utilizator

voturi
3

Recursivitatea pe un copac cu 100.000 de noduri , nu ar trebui să fie o problemă în cazul în care este echilibrat. Adâncimea ar fi doar poate 17, ceea ce nu ar folosi foarte mult stivă în implementările afișate. (log2(100,000) = 16.61). Deci , se pare că poate codul care este construirea arborelui de echilibrare nu - l corect.

Publicat 10/11/2011 la 01:02
sursa de către utilizator

voturi
1

Poate fi aveți nevoie pentru a calcula acest lucru în timp ce faci inserția. Stocați înălțimile de noduri, adică adaugă un câmp întreg ca înălțime în obiectul Nod. De asemenea, au înălțime de contoare și frunze pentru copac. Când introduceți un nod, în cazul în care societatea-mamă este (era) o frunză, schimbarea doesnt numărul de frunze, dar dacă nu, crește numărul de frunze de 1. De asemenea, înălțimea noului nod este înălțimea părintelui + 1, prin urmare, în cazul în care este mai mare decât înălțimea actuală a arborelui, apoi actualizați. Este o tema, asa ca am obiceiul de ajutor cu codul real

Publicat 10/11/2011 la 01:05
sursa de către utilizator

voturi
2

Am găsit această pagină foarte edificator , deoarece se vorbește despre mecanica de conversie a unei funcții care utilizează recursivitate la una care utilizează iterație.

Are exemple de cod care prezintă, de asemenea.

Publicat 10/11/2011 la 01:06
sursa de către utilizator

voturi
1

Echilibrați copac ocazional. În cazul în care arborele este obtinerea StackOverflow pe FindHeight (), ceea ce înseamnă că arborele este mod dezechilibrat. În cazul în care arborele este echilibrat , el ar trebui să aibă doar o adâncime de aproximativ 20 de noduri de 100000 elemente.

Cel mai simplu (dar destul de lent) modul de re-echilibrare arbore binar dezechilibrat este de a aloca o serie de TItemsuficient de mare pentru a deține toate datele din copac, introduceți toate datele în el , în ordine sortată și ștergeți toate din nodurile . Apoi reconstrui arborele de matrice recursiv. Rădăcina este nodul în mijloc. root->lefteste mijlocul de jumătatea stângă, root->righteste mijlocul de jumătatea din dreapta. Se repetă recursiv. Acesta este cel mai simplu mod de a reechilibra, dar este slowish și ia temporar o mulțime de memorie. Pe de altă parte, trebuie doar să faci acest lucru atunci când detectează că arborele este foarte dezechilibrat, (adâncimea pe insert este mai mare de 100).

Celălalt (mai bună), opțiunea este de a echilibra timpul inserturi. Modul cel mai intuitiv de a face acest lucru este de a ține evidența numărului de noduri sunt sub nodul curent. În cazul în care copilul din dreapta are mai mult de doua ori mai multe noduri „copil“ ca și copilul din stânga, „Rotate“ a plecat. Si invers. Sunt instrcutions cu privire la modul de a face copac se rotește peste tot pe internet. Acest lucru face inserții ușor mai lent, dar atunci nu au tarabe masive ocazionale că prima opțiune creează. Pe de altă parte, trebuie să actualizeze în mod constant toate „copii“ contează pe măsură ce faci se rotește, ceea ce nu este banală.

Publicat 10/11/2011 la 01:08
sursa de către utilizator

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