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

Head pointer doesn't contain child nodes in Binary Tree

我正在复制一棵二叉树,我遇到了一个问题,我的新树的根指针最终只包含要复制的第一个节点,没有其他节点。我认为这个问题与以下事实有关:当我在辅助函数的递归中传递指针时,出于某种原因,它们没有被重新分配给新的节点内存地址。就像在 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;
    }

检查您的全局变量 first_timeref

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

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

你这里有几个问题。

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

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

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

这是一个固定版本:

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 函数写入 return 指向复制树的指针? 基本上摆脱第 2 个参数,并分配当前树的副本,向下递归,将每个子副本附加到当前节点父副本,并且 return 父节点:

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

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