【问题标题】:C++ Binary Tree Stack OverflowC++ 二叉树堆栈溢出
【发布时间】:2014-12-07 11:03:53
【问题描述】:

好的,我已经调试了几个小时了,但还是无处可去。我正在尝试测试一个简单的递归使用二叉树。

在测试时,我在 main 的 print_attributes 函数的第三次调用中遇到堆栈溢出(如下所述)。对调用堆栈的快速检查表明,它充满了对 binTree 的 binTree 高度(Node * node) 的数百次调用(也在下面注明)。当我“转到”调用堆栈中的调用时,它会将我带到 size(Node * node) 对 leftside = size(node->left) 的调用(也在下面提到)。我不知道这应该表明什么,因为这些函数都不会互相调用。

这是发生堆栈溢出时编译器正确显示的图像(我使用的是 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;
}

【问题讨论】:

    标签: c++ pointers recursion binary-tree stack-overflow


    【解决方案1】:

    首先,在您的类binTree 中,size()height() 方法都具有以下行:

    if (root = 0)
    

    显然这应该是==

    实际的堆栈溢出问题似乎是由您的insert 函数引起的。它通过引用获取第一个参数node。因此,当您使用insert(root, t) 调用它时,node 最终会作为对root 的引用。当在insert 中分配新节点时,root 被设置为指向新节点,这也改变了node 引用。

    如果您使用调试器在 insert 函数的顶部设置断点并逐步执行,则可以观察值的变化。

    这意味着rootnode 是同一个东西,所以当你设置node-&gt;left = nnode-&gt;right = n 时,节点最终会指向自己。

    修复它所需要做的就是将insert 的定义更改为通过值而不是引用传递node

    void insert(Node < T >* node, const T& t) // private version of insert ( )
    

    【讨论】:

    • 感谢您的回复。我修复了 '= 0' 的问题并更改了插入的定义,因为这确实有意义。我已经更新了上面的代码以反映这一点。然而,不幸的是,同样的问题仍然存在。编译器仍然指向相同的代码行。
    • 它为我解决了这个问题(因为它不再进入无限循环并崩溃)。也许发布一个完整的可编译示例,这样我们就可以确保我们从完全相同的点开始。
    • 您是否真的尝试在调试器中单步执行以查看问题所在?只需查看指针的值就足以找到错误。
    • 好吧,事实证明问题在于 Visual Studio 实际上并没有重新编译我的 bintree 类,而我认为它是,当我修复该程序运行良好时。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-10
    • 2013-08-10
    • 1970-01-01
    • 2017-04-24
    • 2015-07-25
    • 1970-01-01
    • 2021-10-16
    相关资源
    最近更新 更多