Переполнение стека в двоичном дереве C ++

0

Хорошо, я отлаживаю это в течение нескольких часов, и я никуда не уйду. Я пытаюсь проверить прямое двоичное дерево, использующее рекурсию.

При тестировании я получаю переполнение стека при третьем вызове в основной функции print_attributes (см. Ниже). Быстрый просмотр стоп-кадра показывает, что он содержит сотни вызовов высоты binTree binTree (узел Node <T> *) (также отмечено ниже). Когда я "перехожу к" вызову из стека вызовов, он принимает меня к размеру (узлу <T> * node) вызов leftside = size (node-> слева) (также отмечено ниже). Я не знаю, что это должно указывать, потому что ни одна из этих функций не вызывает друг друга.

Здесь изображение того, что компилятор говорит правильно, когда происходит переполнение стека (я использую VS2013): http://puu.sh/ca3ti/e00f653282.png

Затем вот изображение компилятора, после взлома и нажатия любой из вызовов height() в стеке вызовов: http://puu.sh/ca2Qz/d35348ccce.png

Учитывая, что он (кажется,) вставляет узлы в древовидный тон непосредственно перед использованием функции bintree height() и/или size(), я понятия не имею, почему в этой же функции возникают проблемы. Мне жаль, что я не смог более четко объяснить, в чем проблема. Я кодировал несколько лет, но я действительно потерял это. Я попытался предоставить как можно больше информации. Большое вам спасибо всем, кто не торопится, чтобы помочь с этим.

Класс узла:

#include "340.h"

#ifndef H_NODE
#define H_NODE

// definition for class of nodes in bin tree

template < class T > class binTree; // forward declaration

template < class T >
class Node {
friend class binTree < T >;         // binTree is friend
public:
    // default constructor
    Node ( const T& x = T ( ), Node < T >* l = 0, Node < T >* r = 0 ) :
        data ( x ), left ( l ), right ( r ) { }
private:
    T data;                         // data component
    Node < T > *left, *right;       // left and right links
};
#endif

Класс NodeTree:

#include "Node.h"

#ifndef H_TREE
#define H_TREE

template < class T > class binTree {
public:
    binTree(Node < T >* emptyroot = nullptr) : // default constructor
        root(emptyroot) { }

    bool empty() const // checks if tree empty
    {
        if (root == 0)
            return true;
        else
            return false;
    }

    unsigned size() const // returns no of nodes
    {
        if (root == 0)
            return 0;
        else
            return size(root);
    }

    unsigned height() const // returns height of tree
    {
        if (root == 0)
            return 0;
        else
            return height(root);
    }

    virtual void insert(const T& t) // inserts a node in shortest subtree
    {
        if (empty())
        {
            Node< T >* n = new Node< T >;
            n->data = t;
            root = n;
        }
        else
            insert(root, t);
    }
protected:
    Node < T >* root; // root of tree
private:
    unsigned size(Node < T >* node) const // private version of size ( )
    {
        unsigned leftside;
        unsigned rightside;

        if (node->left == 0)
            leftside = 0;
        else
            leftside = size(node->left); //******issue(?) here******

        if (node->right == 0)
            rightside = 0;
        else
            rightside = size(node->right);

        return(leftside + rightside + 1);
    }

    unsigned height(Node < T >* node) const // private version of height ( ) 
//*****issue(?) here************
    {
        unsigned leftside;
        unsigned rightside;

        if (node->left == 0)
            leftside = 0;
        else
            leftside = height(node->left);

        if (node->right == 0)
            rightside = 0;
        else
            rightside = height(node->right);

        return 1 + max(leftside, rightside);
    }

    void insert(Node < T >* node, const T& t) // private version of insert ( )
    {
        if (node->left == 0)
        {
            Node< T >* n = new Node< T >;
            n->data = t;
            root = n;

            node->left = n;
            return;
        }
        else if (node->right == 0)
        {
            Node< T >* n = new Node< T >;
            n->data = t;
            root = n;

            node->right = n;
            return;
        }

        unsigned lefth = height(node->left);
        unsigned righth = height(node->right);

        if (lefth <= righth)
        {
            insert(node->left, t);
        }
        else
        {
            insert(node->right, t);
        }       
    }
};

#endif

Главный:

#include "binTree.h"

// vectors used in testing
const vector < int > A { 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12,
        13, -14, 15 };

// prints out val passed as argument
template < class T > void print ( T& x ) { cout << x << ' '; }

// increments val passed as argument
template < class T > void increment ( T& x ) { x++; }

// decrements val passed as argument
template < class T > void decrement ( T& x ) { x--; }

// prints out attributes, such as size and height of bin tree,
// and prints out data val in each node in inorder, preorder,
// and postorder

template < class T >
void print_attributes ( binTree < T >& tree, const string& name )
{
    cout << name; // print name of tree

    // check if tree is empty
    cout << ": tree is " << ( tree.empty ( ) ? "" : "not " ) << "empty\n";

    // print size and height of tree
    cout << "\tno of nodes    = " << setw ( 2 ) << tree.size ( )
         << "\n\theight of tree = " << setw ( 2 ) << tree.height ( )
         << endl << endl; //*******issue here************

    system("pause");
    return 0;
}
Теги:
pointers
recursion
binary-tree
stack-overflow

1 ответ

1
Лучший ответ

Во-первых, в вашем классе binTree size() и height() имеют следующую строку:

if (root = 0)

Очевидно, что это должно быть ==.

Фактическая проблема, по-видимому, вызвана вашей функцией insert. Он принимает первый параметр, node по ссылке. Поэтому, когда вы вызываете его со insert(root, t), node заканчивается ссылкой на root. Когда новый узел распределяется во insert, root устанавливается для указания на новый узел, и это также изменяет ссылку на node.

Если вы используете отладчик для установки точки останова в верхней части своей функции insert и выполните шаг, вы можете наблюдать за изменением значений.

Это означает, что root и node - одно и то же, поэтому, когда вы устанавливаете node->left = n или node->right = n узел заканчивается, указывая на себя.

Все, что вам нужно сделать, чтобы исправить это, - это изменение определения insert для передачи node по значению, а не по ссылке:

void insert(Node < T >* node, const T& t) // private version of insert ( )
  • 0
    Спасибо за ответ. Я исправил «= 0» и изменил определение вставки, потому что это имеет смысл. Я обновил код выше, чтобы отразить это. Тем не менее, та же проблема все еще сохраняется, к сожалению. Компилятор по-прежнему указывает на те же строки кода и все.
  • 0
    Это исправило проблему для меня (в том, что оно больше не входило в бесконечный цикл и падало). Возможно, опубликуйте полный скомпилированный пример, чтобы мы могли быть уверены, что начинаем с одной и той же точки.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню