【问题标题】:C++ Tree pointer issuesC++ 树指针问题
【发布时间】:2016-11-21 01:23:15
【问题描述】:

我对二叉搜索树指针有疑问,无法确定原因。我有一个函数,我取两棵树并在预定位置交换两棵树的子树。这是进行上述交换的代码。

opNode* tmp = new opNode();
opNode* tmp2 = new opNode();
tmp = this->clone();
tmp2 = secondParentNode->clone();
this->operation = tmp2->operation;
this->val = tmp2->val;
this->lChild = tmp2->lChild;
this->rChild = tmp2->rChild;
secondParentNode = tmp;

此时我已经确定了要交换的每个子树的位置。 "this" 指针代表第一个交换点,secondParentNode 是一个 opNode 指针,代表第二个。

这里有两个问题:

第一个是交换可以创建一个节点只有一个孩子的情况。我无法确定这是如何发生的。

第二,也许是相关的信息,一旦 this->lChild 设置为 tmp2->lChild 并且 this->rChild = tmp2->rChild,我插入了一个检查是否是 secondParentNode->lChild 或 secondParentNode -> rChild 为空。这至少会导致段错误。

克隆(深拷贝)功能不起作用吗?如果是这样,为什么不呢?对于可能导致这些问题的任何想法,我们将不胜感激。

opNode 是我的节点类:

struct opNode
{
    string operation;
    double val;
    opNode* lChild;
    opNode* rChild;
    opNode* clone();
};

以及相关的克隆功能:

opNode* opNode::clone()
{
    if(this != nullptr)
    {
        opNode* n = new opNode();
        n->val = val;
        n->operation = operation;
        n->rChild = rChild->clone();
        n->lChild = lChild->clone();
        return n;
    }
    return nullptr;
}

编辑* 根据要求,交换功能。 randPoint1 和 randPoint2 由 uniform distribution 确定:

uniform_int_distribution<int> dist(0, mate[k].root->count(0) - 1);

其中 mate[k] 是根树指针,count 定义为:

int opNode::count(int c)
{
    if(this != nullptr)
    {
        c++;
        if(lChild != nullptr)
            c += lChild->count(0);
        if(rChild != nullptr)
            c += rChild->count(0);
        return c;
    }
    return 0;
}

兑换功能:

void opNode::recombination(opNode*& secondParentNode, int& randPoint1, int& randPoint2, bool& done)
{
    if(done)
        return;
    if(secondParentNode != nullptr && !done)
    {
        if(randPoint2 > 0 && secondParentNode->lChild != nullptr)
        {
            randPoint2--;
            recombination(secondParentNode->lChild, randPoint1, randPoint2, done);
        }

        if(randPoint2 > 0 && secondParentNode->rChild != nullptr)
        {
            randPoint2--;
            recombination(secondParentNode->rChild, randPoint1, randPoint2, done);
        }
    }
    if(this != nullptr && randPoint2 == 0 && !done)
    {
        if(randPoint1 > 0 && lChild != nullptr)
        {
            randPoint1--;
            lChild->recombination(secondParentNode, randPoint1, randPoint2, done);
        }
        if(randPoint1 > 0 && rChild != nullptr)
        {
            randPoint1--;
            rChild->recombination(secondParentNode, randPoint1, randPoint2, done);
        }
    }
    if(this != nullptr && secondParentNode != nullptr && randPoint1 == 0 && randPoint2 == 0 && !done)
    {
        opNode* tmp = new opNode();
        opNode* tmp2 = new opNode();
        tmp = this->clone();
        tmp2 = secondParentNode->clone();
        this->operation = tmp2->operation;
        this->val = tmp2->val;
        this->lChild = tmp2->lChild;
        this->rChild = tmp2->rChild;
        secondParentNode = tmp;
    }
}

【问题讨论】:

  • 顺便说一句(我投票关闭,因为您没有提供有用的示例),但是您的第一个代码 sn-p 出于某种原因泄漏了两个节点。此外,“无法阅读的文字墙”也不适合提问。
  • 在这种情况下,你认为什么是有用的例子?
  • 虽然二叉树并不是最复杂的数据结构,但从tmp=new OpNode();... tmp =this-_clone()this != nullptr 可以明显看出您仍然是初学者。即使我是你的同事,我也不会开始调试这个。问题是你写了太多没有测试的代码。
  • 我已经迫不及待地想进入下一个级别,我会说 tmp = clone() 或 if(this)。非常规是否等同于缺乏知识?它略显冗长。我对我自己构建的这种数据结构的工作不多,所以在这方面你是正确的。我还测试了我需要单独编写的每个函数,并观察到了积极的结果。在这种情况下,我想它会显示一个彻底的驱动程序功能的价值。虽然,在这种情况下,我缺乏解决这种极端情况的知识,所以我不会写任何驱动程序来帮助。因此问题。
  • This 是一个有用的例子的定义。讽刺也不好看。当 MSalters 指出 if(this != nullptr) 风格不佳时,这并不是因为您可以改用 if(this),而是因为在 null 对象上调用方法是无效的,因此您在到达之前已经调用了未定义的行为查看。如果它可能是真的,那么您的代码已经是静态错误的。如果不能,则说明您编写了额外的逻辑,表明您不了解自己的代码的行为方式。

标签: c++ pointers binary-tree deep-copy


【解决方案1】:

如果rChildlChildnullptr,则调用rChild-&gt;clone();lChild-&gt;clone() 将导致分段错误。

我们可以将函数改写为:

void opNode::clone(opNode* n)
{
    if (n)
    {
        n->val = val;
        n->operation = operation;
        if (rChild)
        {
            if (n->rChild)
            {
                 // release all right children.
            }
            n->rChild = new opNode;
            clone(n->rChild);
        }

        if (lChild)
        {
            if (n->lChild)
            {
                 // release all left children nodes.
            }
            n->lChild = new opNode;
            clone(n->lChild);
        }
    }
}

兑换码可以简化为:

opNode* tmp = new opNode;
clone(tmp);
secondParentNode->clone(this);
tmp->clone(secondParentNode);

【讨论】:

  • 我不认为空子的段错误是问题。我以前会成功使用克隆功能。除非这解释了为什么前面的克隆函数可能定义一个孩子而不是另一个孩子,假设一个有效的二叉搜索树作为输入。此外,此修改后的代码会导致 malloc.c:3302 中出现单独的段错误。
  • 在创建opNode时,成员rChildlChild是否被初始化为nullptr?当成员初始化为nullptr 时,如果opNode 没有左或右孩子,代码将立即segfaut。
  • 这是不正确的。您可以调用空类指针的函数。我测试了这段代码,并且产生了预期的结果: opNode* n = new opNode(); int a = n->lChild->count(0); a = 0; cout
  • 我们能知道是什么输入导致问题1吗?该问题是始终出现在此输入中还是偶尔出现?您能显示导致问题 2 的代码段吗?
  • 问题 1:我有理由确定在交换 2 棵大小为 1 的树(每棵树是单个节点)的根(整个树)时总是会发生这种情况。如果我发现任何信息,我会用更多信息更新它。问题 2:if((lChild == nullptr &amp;&amp; rChild != nullptr) || (rChild == nullptr &amp;&amp; lChild != nullptr) || (secondParentNode-&gt;rChild == nullptr &amp;&amp; secondParentNode-&gt;lChild != nullptr) || (secondParentNode-&gt;lChild == nullptr &amp;&amp; secondParentNode-&gt;rChild != nullptr)) 对不起,我不知道如何更好地格式化这个,但是这个 if 语句导致了崩溃。
猜你喜欢
  • 1970-01-01
  • 2010-11-15
  • 2011-08-02
  • 2011-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多