头指针不包含二叉树中的子节点

Posted

技术标签:

【中文标题】头指针不包含二叉树中的子节点【英文标题】:Head pointer doesn't contain child nodes in Binary Tree 【发布时间】:2020-10-30 01:08:41 【问题描述】:

我正在复制一棵二叉树,但我遇到了一个问题,即我的新树的根指针最终只包含要复制的第一个节点,而没有其他节点。我认为这个问题与这样一个事实有关,即当我在辅助函数的递归中传递指针时,由于某种原因,它们没有被重新分配给新的节点内存地址。就像在helper(t1->left, t2->left) t2->left 实际上永远不会成为我想要它拥有的值,它保持为空。

   bool first_time = true;
   TreeNode* ref = NULL;
    void helper(TreeNode* t1, TreeNode* t2) 
        if(t1) 
            t2 = new TreeNode(t1->val);
            if(first_time) 
                ref = t2;
                first_time = false;
            
            helper(t1->left, t2->left);
            helper(t1->right, t2->right);
        
        
    
    TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) 
        TreeNode* tree1 = new TreeNode(1);
        tree1->left = new TreeNode(2);
        tree1->right = new TreeNode(3);
        helper(tree1, NULL);
        return ref;
    

【问题讨论】:

【参考方案1】:

这里有几个问题。

首先,reffirst_time 是严重的缺陷,您应该避免编写具有这种全局状态的代码。它不是可重入的,也不是线程安全的。

其次,您尝试写入 t2 指针并将调用者的指针更改为该值。但是,您传递的是 t2 的副本,因此对其的写入将会丢失。

清理它并不需要太多,只需更改您的函数以获取 对指针的引用,然后写入 t2 将持续返回给调用者。注意,t2 是一个“out”参数,所以初始调用者会得到通过这个指针返回的树副本。

这是一个固定版本:

void helper(TreeNode* t1, TreeNode*& t2) 
    if(t1) 
        t2 = new TreeNode(t1->val);
        helper(t1->left, t2->left);
        helper(t1->right, t2->right);
      

这是您的测试函数的样子:

TreeNode* copyTest() 
    TreeNode* tree1 = new TreeNode(1);
    tree1->left = new TreeNode(2);
    tree1->right = new TreeNode(3);
    
    TreeNode* tree2 = nullptr;
    helper(tree1, tree2);  // tree2 is written to as new root.
    return tree2;

但如果不需要 out 参数,一般不建议使用。

为什么不编写你的 copyTree 函数来返回一个指向复制树的指针? 基本上去掉in中的第二个参数,分配当前树的一个副本,向下递归,将每个子副本附加到当前节点的父副本,并返回父节点:

TreeNode* copyTree(TreeNode* tree) 
    TreeNode* ret = nullptr;
    if (tree) 
        ret = new TreeNode(tree->val);
        ret->left = copyTree(tree->left);
        ret->right = copyTree(tree->right);
    
    return ret;

除非您非常小心,否则这不是防止泄漏的好方法,但它有助于理解递归和树结构。

【讨论】:

这条评论给了我很大的帮助,我非常感谢你提到的所有额外建议,让我成为更好的程序员【参考方案2】:

检查您的全局变量 first_timeref

if (first_time) 
  ref = t2;           // global
  first_time = false; // global set to never go here again

这实际上是您的问题的根源 - 一旦您将第一个节点传递给您的函数,您就更改了其他全局变量 ref,之后再也不会在任何地方更改它。因此,基本上,在每个递归调用中,您都会使用悬空指针泄漏内存。 可能,您应该将参数 first_time 传递给您的函数,并可能将 ref 作为可分配参数传递

【讨论】:

以上是关于头指针不包含二叉树中的子节点的主要内容,如果未能解决你的问题,请参考以下文章

JZ8 二叉树的下一个结点

剑指offer 二叉树的下一个结点(Java)

剑指 の 精选详解「二叉树中序遍历的下一个结点」两种解法

二叉树中序遍历的下一个节点

剑指offer系列31-----二叉树的下一个节点

求二叉树中最大的二叉搜索子树的头节点