为什么我的二叉树覆盖了它根的叶子?

Why Is My Binary Tree Overwriting The Leaves Of Its Root?

我已将我的问题确定为这个特定函数,它是我的二叉树的辅助函数。在这个函数调用之前有一个节点,但它似乎只是替换了那个节点而不是增长它。当我在脑海中查看我的代码时,一切都有意义,但我无法弄清楚我做错了什么。

这里是调用add的函数:

void BSTree::Insert(Client &newClient) {
    if (isEmpty())
    {
        Node *newNode = new Node(newClient);
        this->root = newNode;
    }
    else
        add(this->root, newClient);
}

这是我的 add() 函数:

BSTree::Node* BSTree::add(Node *node, Client &newClient) // helper function for Insert()
{
    if (node == nullptr)
        {
            Node *newNode = new Node(newClient);
            //node = newNode; // already tried adding this in
            return newNode;
        }
    if (newClient.clientID < node->pClient->clientID)
        return node->left = add(node->left, newClient); // already tried just returning add()
    else
        return node->right = add(node->right, newClient);
}

由于这是你的问题,我将解释你的代码在做什么。想象一下,您已经有了一个成熟的二叉树,并且您正在向树中添加一个节点。当你到达这条线时

return node->left = add(node->left, newClient);

执行了三个单独的指令:

  1. newClient通过add()添加到node的左分支。
  2. 节点的左子节点设置为 add() 的 return 值。
  3. 赋值的右侧 (RHS) return 由父函数编辑。

问题出在数字 2 上。如果您要添加的树已经成熟,则在遍历树时更改节点的左子节点将导致您观察到的覆盖效果。事实上,问题不仅仅是覆盖树叶。由于您使用了 new 关键字,被覆盖的节点仍然分配了堆 space,永远不会被删除并导致内存泄漏。

这里有一些想法可以帮助您走上正确的方向:

您的 insert() 函数确保您第一次调用 add() 时,不会将 nullptr 作为第一个参数传递。利用这一点,并通过在执行递归调用之前检查 nullptr 来确保 nullptr 永远不会传递到 add() 函数。将 add() 的 return 类型更改为 void。您不再需要检查节点是否为 nullptr。这里有一些伪代码可以指导你

void add(node, val)
    if val < node.val
        if node.left exists
            add(node.left, val)
        else
            make a new object and set node.left to that object
    else
        if node.right exists
            add(node.right, val)
        else
            make a new object and set node.right to that object

你的逻辑有问题。首先,有一个 insert() 方法,你应该这样写以便更好地理解:

void BSTree::Insert(const Client &newClient) // use const to prevent modification
{
    if (isEmpty()) { root = new Node(newClient); }
    else { add(this->root, newClient); }
}

这样您就可以在 BSTree 中的 'root' 指针的帮助下直接在根目录下创建一个新对象。

现在,关于 add() 方法。您作为参数传递的 'node' 是指针变量的副本,因此实际指针值不会更改。看到这个:

BSTree::Node* BSTree::add(Node *node, Client &newClient) //logical error

您需要像这样使用 'Node* &node':

通过引用传递节点*
BSTree::Node* BSTree::add(Node* &node, const Client &newClient)

为什么二叉树会覆盖其叶子的根?答案: 您使用 return 语句的递归调用是完全错误的。

return node->left = add(node->left, newClient);

add(node->left, newClient) 总是 return 叶子的地址,而您正在 returning 这个值。它进行递归调用,直到到达叶子位置。

结论:既然BUG多,建议大家慎重重写逻辑。 我希望这有帮助! :-)