Stackoverflow wyjątkiem, gdy zjeżdżamy BST

głosy
4

Mam wdrożenia BST łącza oparte (wyszukiwanie binarne drzewo) w C ++ dla jednego z mojego zadania. Pisałem całą moją klasę i wszystko działa dobrze, ale moje zadanie pyta mnie wykreślić okresie razy dla:

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

To dobrze, mogę wstawić numery ale również pyta mnie wzywać FindHeight()i CountLeaves()metod na drzewie. Moim problemem jest to, że zostały wdrożone dwie funkcje użyciu recursion. Ponieważ mam taką wielką listę numerów Dostaję coraz stackoverflowwyjątek.

Oto moja definicja klasy:

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 () Wykonanie

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 () realizacja

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

Starałem się myśleć o tym, jak można zaimplementować dwie metody bez rekursji, ale jestem zupełnie zakłopotany. Ktoś ma jakieś pomysły?

Utwórz 10/11/2011 o 00:52
źródło użytkownik
W innych językach...                            


5 odpowiedzi

głosy
1

W celu policzenia liści bez rekursji, używają pojęcia iteratora jak STL wykorzystuje do RB-drzewa bazowego std::seti std::map... Tworzenie begin()i end()funkcji dla ciebie drzewo, które indentifies zamówioną pierwszy i ostatni węzeł (w tym przypadku z lewej najbardziej węzeł, a następnie prawym najbardziej węzeł). Następnie należy utworzyć funkcję o nazwie

BinarySearchTreeNode* increment(const BinarySearchTreeNode* current_node)

że dana current_nodepowróci wskaźnik do następnego węzła w drzewie. Należy pamiętać o tym wdrożenie do pracy, trzeba będzie dodatkowy parentwskaźnik w swoim noderodzaju, aby pomóc w procesie iteracji.

Twój algorytm increment()będzie wyglądać mniej więcej tak:

  1. Sprawdź, czy istnieje prawo-dziecko bieżącego węzła.
  2. Jeśli istnieje prawo-dziecko, należy chwilę pętli, aby znaleźć najbardziej lewy-węzeł tego prawego poddrzewa. To będzie „next” węzeł. W przeciwnym razie przejdź do kroku 3.
  3. Jeśli nie ma na prawym dziecko bieżącego węzła, a następnie sprawdzić, czy bieżący węzeł jest lewym dzieckiem swojego węzła nadrzędnego.
  4. Jeśli krok nr 3 jest prawdą, wtedy „next” węzeł jest węzeł nadrzędny, dzięki czemu można zatrzymać się w tym momencie, w przeciwnym razie przejdź do następnego kroku.
  5. Jeśli etap # 3 był fałszywy, a następnie bieżący węzeł jest prawym dziecko od rodzica. Tak więc trzeba będzie ruszać do następnego węzła nadrzędnego za pomocą pętli while, aż natkniesz się na węźle, który jest lewym dzieckiem swojego węzła nadrzędnego. Rodzic z tego węzła lewej dziecko będzie zatem „next” węzeł, a można zatrzymać.
  6. Wreszcie, jeśli krok nr 5 powrót do korzeni, a następnie bieżący węzeł jest ostatni węzeł w drzewie, a iterator osiągnął koniec drzewa.

W końcu trzeba mieć bool leaf(const BinarySearchTreeNode* current_node)funkcję, która będzie testować, czy dany węzeł jest węzłem liść. W ten sposób funkcja licznika może po prostu iteracyjne choć drzewa i znaleźć wszystkie węzły liści, wracając ostateczną liczbę raz to zrobić.

Jeśli chcesz zmierzyć maksymalną głębokość niezrównoważonej drzewa bez rekursji, będzie w drzewo za insert()funkcję, trzeba śledzić głębokości, że węzeł został wstawiony na. Może to być po prostu zmienna w swoim noderodzaju, który jest ustawiany, gdy węzeł jest włożona w drzewie. Następnie można wykonać iterację trzech, i znaleźć maksymalną głębokość liściu-węzła.

BTW, złożoność tej metody jest niestety będzie O (N) ... nigdzie w pobliżu tak ładne jak O (log N).

Odpowiedział 10/11/2011 o 01:01
źródło użytkownik

głosy
3

Rekursji na drzewie z 100,000 węzłów nie powinno być problemem, jeśli jest zrównoważony. Głębokość byłoby tylko może 17, które nie wykorzystują bardzo dużo stos w implementacjach przedstawionych. (log2(100,000) = 16.61), Tak więc wydaje się, że może to kod, który buduje drzewo nie jest równoważenie go prawidłowo.

Odpowiedział 10/11/2011 o 01:02
źródło użytkownik

głosy
1

Mogą być potrzebne do obliczenia tego robiąc wkładkę. Przechowywać wyżyny węzłów, czyli dodać pole całkowitą wysokość jak w obiekcie węzła. Również wysokość lady i liści na drzewie. Po wstawieniu węzła, jeśli jego rodzic jest (był) liść, zmiana robi liczba liści, ale jeśli nie, należy zwiększyć liczbę liści o 1. Również wysokość nowego węzła jest rodzica wysokość + 1, a więc jeśli to jest większa od bieżącej wysokości drzewa, następnie zaktualizować go. Jego praca, więc przyzwyczajenie pomoc rzeczywisty kod

Odpowiedział 10/11/2011 o 01:05
źródło użytkownik

głosy
2

Znalazłem tę stronę bardzo pouczające, ponieważ opowiada o mechanice konwersji funkcję, która używa rekursji do jednego, który używa iteracji.

Ma przykłady pokazujące, jak również kod.

Odpowiedział 10/11/2011 o 01:06
źródło użytkownik

głosy
1

Zrównoważyć swoje drzewo sporadycznie. Jeśli drzewo jest coraz stackoverflow na FindHeight (), co oznacza, że drzewo jest sposób niezrównoważony. Jeśli drzewo jest zrównoważony powinien mieć tylko głębokość około 20 węzłów do 100000 elementów.

Najprostszym (ale dość powolny) sposób ponownego równoważenia niezrównoważonego drzewa binarnego jest przydzielić tablicę TItemwystarczająco duże, aby pomieścić wszystkie dane w drzewie, wstawić wszystkie dane do niego w uporządkowanej kolejności i usuwanie wszystkich węzłów , Następnie odbudować drzewa z tablicy rekursywnie. Korzeniem jest węzeł w środku. root->leftJest środkowym lewej połowie, root->rightto na środku prawej połowie. Powtórz rekurencyjnie. Jest to najprostszy sposób, aby zrównoważyć, ale to slowish i zajmuje dużo pamięci tymczasowo. Z drugiej strony, trzeba tylko to zrobić, gdy wykryje, że drzewo jest bardzo niesymetryczne (głębokość na wkładki wynosi więcej niż 100).

Drugi (lepszym) rozwiązaniem jest zachowanie równowagi podczas wstawek. Najbardziej intuicyjny sposób, aby to zrobić, aby śledzić ile węzły są poniżej bieżącego węzła. Jeśli dziecko ma prawo więcej niż dwa razy tyle „dziecko” węzłów jak lewej dziecko „Rotate” w lewo. I wzajemnie. Jest instrcutions jak to zrobić drzewo obraca się w całym Internecie. To sprawia, że ​​wkładki nieco wolniej, ale wtedy nie masz occassional masywne stragany, że pierwsza opcja tworzy. Z drugiej strony, trzeba stale aktualizować wszystkie liczby „dzieci”, jak zrobić obraca się, co nie jest trywialne.

Odpowiedział 10/11/2011 o 01:08
źródło użytkownik

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