Stackoverflow výjimka při přechodu BST

hlasů
4

Mám realizovat propojení na bázi BST s (binární vyhledávací strom) v jazyce C ++ pro jednu z mého úkolu. Napsal jsem celý svůj třídu a vše funguje dobře, ale můj úkol mě ptá, aby pozemek dobu chodu pro:

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

To je v pořádku, mohu vložit čísla, ale i to se mě ptá volat FindHeight()a CountLeaves()metody na stromě. Můj problém je, že jsem provedla dvě funkce použití recursion. Vzhledem k tomu, že mám takový velký seznam čísel Začínám dostat stackoverflowvýjimku.

Tady je moje definice třída:

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 () Provádění

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

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

Snažil jsem se myslet na to, jak mohu implementovat dvě metody bez rekurze, ale jsem úplně pařezy. Každý, kdo má nějaké nápady?

Položena 10/11/2011 v 00:52
zdroj uživatelem
V jiných jazycích...                            


5 odpovědí

hlasů
1

Aby bylo možné počítat listy bez rekurze, použijte koncept iterátor jako STL používá pro RB-stromu je základem std::seta std::map... Vytvoření begin()a end()funkce pro vás strom, který indentifies objednaný první a poslední uzel (v tomto případě levého -most uzel a nejvíce vpravo uzlu). Potom vytvořit funkci nazvanou

BinarySearchTreeNode* increment(const BinarySearchTreeNode* current_node)

že pro daný current_node, vrátí ukazatel na další uzel ve stromě. Mějte na paměti, pro tuto implementaci do práce, budete potřebovat další parentukazatel ve vašem nodetypu na pomoc v procesu iterace.

Váš algoritmus increment()bude vypadat podobně jako následující:

  1. Zkontrolujte, zda je pravé dítě aktuálního uzlu.
  2. Dojde-li k pravé dítě, použijte cyklus while najít nejvíce vlevo uzel tohoto pravého podstromu. To bude „další“ uzel. V opačném případě přejděte ke kroku # 3.
  3. Není-li pravé dítě na aktuálním uzlu, pak zkontrolujte, zda je aktuální uzel je vlevo dítě svého nadřazeného uzlu.
  4. Pokud v kroku # 3 je pravda, pak je „další“ node je nadřazený uzel, takže se můžete zastavit v tomto bodě, v opačném případě přejděte k dalšímu kroku.
  5. V případě, že krok # 3 byl nepravdivý, pak aktuální uzel je pravým dítětem rodiče. Tak budete muset být neustále v pohybu až do dalšího nadřazeného uzlu pomocí while až narazíte na uzlu, který je na levé dítě svého nadřazeného uzlu. Rodič tohoto levé podřízený uzel pak bude „další“ uzel, a vy můžete zastavit.
  6. A konečně, je-li krok # 5 vrátí se do kořenového adresáře, pak je aktuální uzel je poslední uzel ve stromu, a iterace dosáhla konce stromu.

Nakonec budete potřebovat bool leaf(const BinarySearchTreeNode* current_node)funkci, která bude testovat, zda je daný uzel je koncový uzel. Takto si funkce counter můžete jednoduše opakovat když stromu a najít všechny koncové uzly, vrací konečný počet, jakmile je to hotovo.

Pokud chcete měřit maximální hloubku nevyvážené stromu bez rekurze, budete ve vaší stromu insert()funkcí, je třeba sledovat hloubku, že uzel byl vložen při. To může být jednoduše variabilní ve svém nodedruhu, který je nastaven, když je ve stromu vloží uzel. Pak můžete iterovat tři, a najít maximální hloubku listový uzel.

BTW, složitost této metody je bohužel bude O (N) ... zdaleka tak hezký jako O (log N).

Odpovězeno 10/11/2011 v 01:01
zdroj uživatelem

hlasů
3

Rekurze na stromě s 100.000 uzly by neměl být problém, pokud to je dáno. Hloubka by jen asi 17, který by se používat moc stack v implementacích znázorněných. (log2(100,000) = 16.61), Takže se zdá, že možná kód, který se staví strom není to správné vyvážení.

Odpovězeno 10/11/2011 v 01:02
zdroj uživatelem

hlasů
1

Může být potřeba počítat to přitom vložku. Uložení výšek uzlů, tedy přidat pole celé číslo jako výška v objektu uzlu. Také mají výšku pulty a listí na stromě. Vložíte-li uzel, pokud jeho rodič (bylo) list, počet listů změna doesnt, ale pokud ne, zvýší počet listů od 1. Také výška nového uzlu je rodiče výška + 1, tedy v případě, že je větší než je současná výška stromu, poté jej aktualizovat. Jeho úkoly, takže jsem zvyklý pomoc při skutečném kódu

Odpovězeno 10/11/2011 v 01:05
zdroj uživatelem

hlasů
2

Našel jsem tuto stránku velmi poučné, protože hovoří o mechanismu převodu funkce, která používá rekurzi, aby ten, který využívá iteraci.

Má příklady, které prokazují kód stejně.

Odpovězeno 10/11/2011 v 01:06
zdroj uživatelem

hlasů
1

Vyvážit svůj strom příležitostně. Pokud váš strom je stále StackOverflow na FindHeight (), to znamená, že váš strom je způsob nevyvážená. V případě, že strom je vyvážená, že by měl mít pouze hloubku asi 20 uzlů na 100000 prvky.

Nejjednodušší (ale poměrně pomalé) způsob, jak re-vyrovnání nevyváženého binárního stromu je přidělit pole TItemdostatečně velká, aby držet všechna data ve stromu, vložit všechna data do ní v seřazeném pořadí, a odstranit všechny uzly , Pak znovu strom z pole rekurzivně. Kořen je uzel ve středu. root->leftje uprostřed levé poloviny, root->rightje uprostřed pravé poloviny. Opakujte rekurzivně. To je nejjednodušší způsob, jak vyvážit, ale je to slowish a vyváží velké množství paměti dočasně. Na druhou stranu, budete mít jen to, když zjistíte, že strom je velmi nevyvážený, (hloubka na vložce je více než 100).

Možnost druhá (lepší) je vyrovnat během vložek. Nejvíce intuitivní způsob, jak to udělat, je sledovat, kolik uzly jsou pod aktuálním uzlu. V případě, že právo dítěte má více než dvakrát tolik „dítě“ uzly jako levé dítě, „otočit“ odešel. A vice-versa. Je tu instrcutions o tom, jak k tomu stromu se otáčí po celém internetu. To dělá vložky mírně pomalejší, ale pak nemáte občasné masivní prodejní stánky, že první volba vytvoří. Na druhou stranu, budete muset neustále aktualizovat všechny „dětí“ se počítá jako vy se otáčí, což není triviální.

Odpovězeno 10/11/2011 v 01:08
zdroj uživatelem

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