这样会不会导致指针悬空?

这是二叉查找树的删除,书上的代码实现,最后delete oldNode时不会导致前一个结点指针悬空么?

void remove( const Comparable &x, BinaryNode*&t)
if(t== NULL)
return; // Item not found; do nothing
 if(x< t->element )remove (x, t->left);
else if( t->element<x)remove( x, t->right );
else if( t->left != NULL && t-> right != NULL) // Two children {
t->element= findMin( t->right )->element;
remove( t->element, t->right );
}
else
{
BinaryNode *oldNode=t;
t=(t->left!= NULL)?t->left:t->right;
delete oldNode;
}


在这段二叉查找树的删除代码中,确实存在一个问题,即在执行delete oldNode;后,前一个节点的指针会悬空。这是因为在删除当前节点时,只是修改了指向当前节点的指针(即BinaryNode*& t),但没有修改指向前一个节点的指针。这可能导致在后续的操作中,访问到已经删除的节点。

可以使用双指针或引用来跟踪前一个节点的指针,确保在删除节点后更新前一个节点的指针指向正确的位置。以下是修改后的代码:

void remove(const Comparable& x, BinaryNode*& t, BinaryNode*& parent) {
    if (t == NULL)
        return; // Item not found; do nothing

    if (x < t->element)
        remove(x, t->left, t);
    else if (t->element < x)
        remove(x, t->right, t);
    else if (t->left != NULL && t->right != NULL) // Two children
    {
        t->element = findMin(t->right)->element;
        remove(t->element, t->right, t);
    } else {
        BinaryNode* oldNode = t;
        if (t->left != NULL)
            t = t->left;
        else
            t = t->right;
        delete oldNode;

        if (parent != NULL) {
            if (parent->left == oldNode)
                parent->left = t;
            else
                parent->right = t;
        }
    }
}

在修改后的代码中,增加了一个BinaryNode*& parent参数,用于跟踪前一个节点的指针。在删除节点后,会根据前一个节点来更新它指向当前节点的指针(t)。这样可以确保删除节点后,前一个节点的指针不会悬空。

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 以下回答来自chatgpt:

    由于本人是一名NLP模型而非IT专家,无法对二叉查找树删除操作的实现代码进行详细讨论。但是,通过阅读相关资料和了解二叉查找树的基本知识,我可以给出以下简要回答:

    在进行二叉查找树删除操作时,可能会出现前一个节点指针悬空的问题。具体而言,如果需要删除的节点只有一个子节点,那么在删除该节点后,该节点的父节点指针所指向的位置可能会成为悬空指针,因为原本需要指向该节点的位置现在没有节点与之对应了。

    为了避免这种情况,通常的解决方案是在进行删除操作前,先判断该节点的情况。如果该节点只有一个子节点,那么可以直接用该节点的子节点替换该节点,并将该节点从树中移除。如果该节点有两个子节点,那么可以先将该节点的前驱或后继节点替换该节点,再将前驱或后继节点从树中移除。

    下面是一个二叉查找树删除操作的示例代码,其中包括了上述解决方案的实现:

    // 定义二叉查找树的节点结构
    struct TreeNode {
        int val;
        TreeNode* left;
        TreeNode* right;
        TreeNode(int x) : val(x), left(NULL), right(NULL) {}
    };
    
    // 在二叉查找树中删除值为val的节点
    TreeNode* deleteNode(TreeNode* root, int val) {
        if (!root) return NULL;
    
        if (root->val == val) {
            // 如果该节点只有一个子节点,直接用子节点替换节点
            if (!root->left) return root->right;
            if (!root->right) return root->left;
    
            // 如果该节点有两个子节点,寻找该节点的前驱节点(也可以选择后继节点)
            TreeNode* p = root->left;
            while (p->right) p = p->right;
    
            // 将前驱节点的值赋给该节点
            root->val = p->val;
    
            // 在左子树中删除前驱节点
            root->left = deleteNode(root->left, p->val);
        }
        else if (root->val > val) {
            root->left = deleteNode(root->left, val);
        }
        else {
            root->right = deleteNode(root->right, val);
        }
    
        return root;
    }
    

    需要注意的是,上述代码中只实现了以寻找前驱节点为基础的删除操作。如果希望采用寻找后继节点的方式进行删除,需要对代码进行适当修改。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^