eccezione StackOverflow quando si attraversa BST

voti
4

Ho implementare un BST link-based (ricerca binaria albero) in C ++ per uno del mio incarico. Ho scritto tutta la mia classe e tutto funziona bene, ma il mio compito mi chiede di tracciare i tempi di funzionamento per:

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

Va bene, posso inserire i numeri, ma mi chiede anche di chiamare il FindHeight()e CountLeaves()metodi sull'albero. Il mio problema è che ho implementato le due funzioni utilizzando recursion. Dal momento che ho una tale una grande lista di numeri che sto ricevendo sempre un stackoverfloweccezione.

Ecco la mia definizione della classe:

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

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

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

Ho cercato di pensare a come posso implementare i due metodi senza ricorsione, ma io sono completamente confusi. Qualcuno ha qualche idea?

È pubblicato 10/11/2011 alle 00:52
fonte dall'utente
In altre lingue...                            


5 risposte

voti
1

Al fine di contare le foglie, senza ricorsione, utilizzare il concetto di un iteratore come lo STL utilizza per la RB-albero di fondo std::sete std::map... Creare un begin()e end()funzioni per voi albero che identifica il primo e l'ultimo nodo ordinata (in questo caso la sinistra nodo -più e quindi il più a destra nodo). Quindi creare una funzione chiamata

BinarySearchTreeNode* increment(const BinarySearchTreeNode* current_node)

che per una data current_node, restituisce un puntatore al nodo successivo nella struttura. Tenete a mente per questa implementazione al lavoro, avrete bisogno di un extra parentpuntatore nel vostro nodetipo per aiutare nel processo di iterazione.

Il vostro algoritmo per increment()sarebbe simile alla seguente:

  1. Verificare se v'è un diritto-figlio al nodo corrente.
  2. Se v'è un diritto-bambino, utilizzare un ciclo while per trovare il nodo più a sinistra di quel sottoalbero destro. Questo sarà il nodo "next". In caso contrario, passare al punto 3 #.
  3. Se non c'è il tasto destro del bambino sul nodo corrente, quindi verificare se il nodo corrente è la sinistra-figlio del suo nodo padre.
  4. Se passo # 3 è vero, allora il nodo "prossimo" è il nodo principale, in modo da poter fermarsi a questo punto, altrimenti passare alla fase successiva.
  5. Se il passo # 3 era falsa, allora il nodo corrente è il diritto del figlio del genitore. In questo modo è necessario continuare a muoversi fino al prossimo nodo padre utilizzando un ciclo while fino a quando ci si imbatte in un nodo che è una sinistra-figlio del suo nodo padre. Il genitore di questo nodo di sinistra-bambino sarà quindi il nodo "next", e ci si può fermare.
  6. Infine, se passo # 5 si torna alla radice, allora il nodo corrente è l'ultimo nodo nella struttura, e l'iteratore ha raggiunto la fine della struttura.

Infine avrete bisogno di una bool leaf(const BinarySearchTreeNode* current_node)funzione che metterà alla prova se un determinato nodo è un nodo foglia. Così si funzione del contatore può semplicemente scorrere anche se l'albero e trovare tutti i nodi foglia, la restituzione di un conteggio finale una volta fatto.

Se si vuole misurare la profondità massima di un albero sbilanciato senza ricorsione, si, nel vostro albero di insert()funzione, hanno bisogno di tenere traccia della profondità che un nodo è stato inserito. Questo può essere semplicemente una variabile nel nodetipo che viene impostato quando il nodo è inserito nella struttura. È quindi possibile scorrere i tre, e trovare la profondità massima di una foglia-nodo.

A proposito, la complessità di questo metodo è, purtroppo, sta per essere O (N) ... affatto così bello come O (log N).

Risposto il 10/11/2011 a 01:01
fonte dall'utente

voti
3

Ricorsione su un albero con 100.000 nodi non dovrebbe essere un problema se è equilibrato. La profondità sarebbe solo forse 17, che non userebbe molto pila nelle implementazioni indicate. (log2(100,000) = 16.61). Così sembra che forse il codice che sta costruendo l'albero non è bilanciamento correttamente.

Risposto il 10/11/2011 a 01:02
fonte dall'utente

voti
1

Può essere che si deve calcolare questo mentre si fa l'inserto. Memorizzare le altezze dei nodi, cioè aggiungere un campo integer come altezza nell'oggetto nodo. Inoltre hanno i contatori di altezza e le foglie per l'albero. Quando si inserisce un nodo, se il suo genitore è (era) una foglia, il cambiamento doesnt conteggio foglia, ma in caso contrario, aumentare il numero di foglie di 1. Anche l'altezza del nuovo nodo è l'altezza dei genitori + 1, quindi se questo è maggiore rispetto all'altezza corrente dell'albero, quindi aggiornarla. Il suo un lavoro, così non lo vorrei aiuto con il codice vero e proprio

Risposto il 10/11/2011 a 01:05
fonte dall'utente

voti
2

Ho trovato questa pagina molto illuminante perché parla la meccanica di conversione di una funzione che utilizza la ricorsione a quella che utilizza iterazione.

Ha esempi che mostrano il codice pure.

Risposto il 10/11/2011 a 01:06
fonte dall'utente

voti
1

Bilancia il tuo albero di tanto in tanto. Se il vostro albero è sempre StackOverflow su FindHeight (), questo significa che il vostro albero è così sbilanciato. Se l'albero è bilanciato dovrebbe avere solo una profondità di circa 20 nodi per 100000 elementi.

Il modo più semplice (ma piuttosto lento) di ri-bilanciamento sbilanciato albero binario è quello di allocare una matrice di TItemabbastanza grande per contenere tutti i dati nella struttura, inserire tutti i dati in esso in modo ordinato, e cancellare tutte i nodi . Poi ricostruire l'albero dalla matrice ricorsivamente. La radice è il nodo nel mezzo. root->leftè al centro della metà sinistra, root->rightè al centro della metà di destra. Ripetere in modo ricorsivo. Questo è il modo più semplice per riequilibrare, ma è slowish e prende un sacco di memoria temporanea. D'altra parte, devi solo fare questo quando si rileva che l'albero è molto sbilanciato, (profondità su inserto è più di 100).

L'altro (migliore) opzione è quella di bilanciare durante inserti. Il modo più intuitivo per fare questo è quello di tenere traccia del numero di nodi sono sotto il nodo attuale. Se il figlio destro ha più del doppio dei nodi "figli" come il figlio sinistro, "Ruota" a sinistra. E viceversa. C'è Instrcutions su come fare albero ruota tutti su Internet. Questo rende inserti leggermente più lento, ma poi non avete occasionali enormi bancarelle che la prima opzione crea. D'altra parte, è necessario aggiornare costantemente tutti i conteggi "bambini" come si fa la rotazione, che non è banale.

Risposto il 10/11/2011 a 01:08
fonte dall'utente

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