Stackoverflow excepción cuando se atraviesa BST

votos
4

Tengo implementar un BST basada en el enlace (árbol binario de búsqueda) en C ++ para uno de mi asignación. He escrito toda mi clase y todo funciona bien, pero mi tarea me pregunta para trazar los tiempos de ejecución para:

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

Eso está bien, puedo insertar los números pero también me pide que llame a la FindHeight()y CountLeaves()métodos en el árbol. Mi problema es que he implementado utilizando las dos funciones recursion. Desde que tengo un una gran lista de números tales que estoy recibiendo conseguir una stackoverflowexcepción.

Aquí está mi definición de clase:

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 () Aplicació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 () aplicación

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

Traté de pensar en cómo puedo aplicar los dos métodos sin recursividad, pero estoy completamente perplejo. ¿Alguien tiene alguna idea?

Publicado el 10/11/2011 a las 00:52
fuente por usuario
En otros idiomas...                            


5 respuestas

votos
1

Con el fin de contar las hojas sin recursividad, utilizar el concepto de un iterador como el STL utiliza para la RB-árbol subyacente std::sety std::map... Crear una begin()y end()función para la que árbol que identifica el primer y el último nodo ordenado (en este caso la izquierda nodo -la mayoría y luego el más a la derecha nodo). A continuación, crear una función llamada

BinarySearchTreeNode* increment(const BinarySearchTreeNode* current_node)

que para una dada current_node, devolverá un puntero al siguiente nodo en el árbol. Tenga en cuenta para esta aplicación al trabajo, se necesita un extra de parentpuntero en su nodetipo para ayudar en el proceso de iteración.

Su algoritmo para increment()vería algo como lo siguiente:

  1. Comprobar para ver si hay un derecho del niño al nodo actual.
  2. Si hay un niño-derecha, utilizar un bucle while para encontrar el nodo más a la izquierda de ese subárbol derecho. Este será el nodo de "siguiente". De lo contrario, vaya al paso # 3.
  3. Si no existe un derecho a los niños en el nodo actual, a continuación, comprobar para ver si el nodo actual es el izquierdo-niño de su nodo padre.
  4. Si el paso # 3 es cierto, entonces el nodo "siguiente" es el nodo padre, por lo que puede detenerse en este punto, de lo contrario ir al paso siguiente.
  5. Si el paso # 3 era falsa, entonces el nodo actual es el derecho del niño de los padres. Por lo tanto tendrá que mantenerse en movimiento hasta el siguiente nodo padre usando un bucle while hasta encontrar un nodo que es un hijo izquierdo de su nodo padre. El padre de este nodo izquierdo niño será entonces el nodo "siguiente", y se puede parar.
  6. Por último, si el paso # 5 le devuelve a la raíz, entonces el nodo actual es el último nodo en el árbol, y el iterador ha llegado al final del árbol.

Por último se necesita un bool leaf(const BinarySearchTreeNode* current_node)función que va a probar si un determinado nodo es un nodo hoja. Así que la función de contador puede simplemente repetir aunque el árbol y encontrar todos los nodos hoja, devolver un recuento final una vez que se hace.

Si se desea medir la profundidad máxima de un árbol desequilibrado y sin recursividad, tendrá, en su árbol de insert()función, que hacer un seguimiento de la profundidad que un nodo se inserta en. Esto puede ser simplemente una variable en su nodetipo que se establece cuando se inserta el nodo en el árbol. A continuación, puede iterar a través de los tres, y encontrar la profundidad máxima de una hoja-nodo.

Por cierto, la complejidad de este método es, por desgracia va a ser O (N) ... nada tan agradable como O (log N).

Respondida el 10/11/2011 a las 01:01
fuente por usuario

votos
3

Recursividad en un árbol con 100.000 nodos no debería ser un problema si se equilibra. La profundidad sólo sería tal vez 17, que no se utilice mucho pila en las implementaciones mostradas. (log2(100,000) = 16.61). Así que parece que tal vez el código que está construyendo el árbol no está equilibrando correctamente.

Respondida el 10/11/2011 a las 01:02
fuente por usuario

votos
1

Puede ser que usted necesita para calcular este mientras se hace la inserción. Almacenar las alturas de los nodos, es decir, añadir un campo de número entero como la altura en el objeto Node. También tienen contadores de altura y hojas para el árbol. Al insertar un nodo, si su padre es (fue) una hoja, el cambio doesnt recuento hoja, pero si no es así, aumentar el número de hojas en 1. También la altura del nuevo nodo es la altura del padre + 1, por lo tanto, si es mayor que la altura actual del árbol, y luego actualizarlo. Es una tarea, por lo que no ayudará con el código real

Respondida el 10/11/2011 a las 01:05
fuente por usuario

votos
2

He encontrado esta página muy esclarecedor porque habla de la mecánica de la conversión de una función que utiliza la recursividad para uno que utiliza iteración.

Tiene que muestran ejemplos de código también.

Respondida el 10/11/2011 a las 01:06
fuente por usuario

votos
1

El balance de su árbol de vez en cuando. Si el árbol está recibiendo stackoverflow en FindHeight (), eso significa que su árbol es manera desequilibrada. Si el árbol está equilibrado que sólo debe tener una profundidad de alrededor de 20 nodos para 100000 elementos.

La forma más sencilla (pero bastante lento) de re-equilibrar árbol binario desequilibrado es asignar una matriz de TItemlo suficientemente grande para contener todos los datos en el árbol, insertar todos sus datos en él en forma ordenada y eliminar todo de los nodos . Luego reconstruir el árbol de la matriz de forma recursiva. La raíz es el nodo en el medio. root->leftes la mitad de la mitad izquierda, root->rightes la mitad de la mitad derecha. Repetir de forma recursiva. Esta es la forma más fácil de reequilibrar, pero es slowish y toma mucha memoria temporal. Por otro lado, es suficiente con hacer esto cuando se detecta que el árbol es muy desequilibrada, (profundidad de inserción es más de 100).

La opción de otra (mejor) es equilibrar durante insertos. La forma más intuitiva de hacer esto es hacer un seguimiento de cuántos nodos están por debajo del nodo actual. Si el hijo derecho tiene más del doble de los nodos "niño" como el hijo izquierdo, "girar" hacia la izquierda. Y viceversa. Hay Instrcutions sobre cómo hacerlo árbol gira por toda la Internet. Esto hace que las inserciones ligeramente más lento, pero entonces usted no tiene puestos masivas ocasionales que crea la primera opción. Por otro lado, hay que actualizar constantemente todos los aspectos "niños" como lo hace al girar, lo que no es trivial.

Respondida el 10/11/2011 a las 01:08
fuente por usuario

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