【问题标题】:Binary Search Tree error when deleting a leaf node删除叶节点时出现二叉搜索树错误
【发布时间】:2018-11-16 01:16:54
【问题描述】:

我正在测试从二叉搜索树中删除节点的函数,但发现我无法删除叶节点。在打印整个树时,Visual Studio 在 in_order 函数中给了我这个错误。 - 抛出异常:读取访问冲突。 树是 0xDDDDDDDD。

想知道如何修复它,因为到目前为止它在所有其他情况下都有效。

void in_order(BinTreeNode* tree) {
    if (tree->left != NULL)
        in_order(tree->left);
    std::cout << tree->value << std::endl;
    if (tree->right != NULL)
        in_order(tree->right);
}


void deleteNodeFromBST(BinTreeNode* root_value, int key_value)
{
    BinTreeNode* selected_node = root_value;
    BinTreeNode* previous_selected_node = NULL;
    bool foundNode = false;

    /* find the node we want to delete */

    while (foundNode == false)
    {
        if (selected_node == NULL)
        {
            return; 
        }

        else
        {
            if (selected_node->value == key_value)
            {
                foundNode = true; 
            }

            else
            {
                previous_selected_node = selected_node;
                if (key_value > selected_node->value)
                    selected_node = selected_node->right;
                else
                    selected_node = selected_node->left; 
            }
        }
    }

    if (foundNode == false)
    {
        return;
    }


    /* if the node has no children, just delete it */

    if (selected_node->left == NULL && selected_node->right == NULL)
    {
        if (previous_selected_node->left == selected_node)
            previous_selected_node->left == NULL;
        else
            previous_selected_node->right = NULL;
        delete selected_node;
        return;
    }

    /* if the node has one child to the left , we replace the node with the child*/

    else if (selected_node->left != NULL && selected_node->right == NULL)
    {
        if (previous_selected_node->left == selected_node)
        {
            previous_selected_node->left = selected_node->left;
            delete selected_node;
            selected_node = NULL;
            return;
        }
        else
        {
            previous_selected_node->right = selected_node->left;
            delete selected_node;
            selected_node = NULL;
            return;
        }
    }

    /* if the node has one child to the right, we replace the node with the child*/

    else if (selected_node->right != NULL && selected_node->left == NULL)
    {
        if (previous_selected_node->right == selected_node)
        {
            previous_selected_node->right = selected_node->right;
            delete selected_node;
            selected_node = NULL;
            return;
        }
        else
        {
            previous_selected_node->left = selected_node->right;
            delete selected_node;
            selected_node = NULL;
            return; 
        }
    }

    /*if the node we want to delete has two children, we find the max value in the left subtree and we replace it */

    else if (selected_node->left != NULL && selected_node->right != NULL)
    {
        BinTreeNode* maxLeftValue = selected_node->left;
        BinTreeNode* maxLeftValuePrev = selected_node; 


        while (maxLeftValue->right != NULL)
        {
            maxLeftValuePrev = maxLeftValue;
            maxLeftValue = maxLeftValue->right;
        }

        selected_node->value = maxLeftValue->value;

        if (maxLeftValue->left != NULL)
        {
            maxLeftValuePrev->right = maxLeftValue->left;
        }
        else
        {
            maxLeftValuePrev = NULL;
        }
        delete maxLeftValue;
        maxLeftValue = NULL;
        return; 
    }
}

int main(int argc, char *argv[])
{
    //BinTreeNode* t = tree_insert(0, 6);
    /*tree_insert(t, 10);
    tree_insert(t, 5);
    tree_insert(t, 2);
    tree_insert(t, 3);
    tree_insert(t, 4);
    tree_insert(t, 11);*/
    BinTreeNode* t = tree_insert(0, 20);
    tree_insert(t, 15);
    tree_insert(t, 19);
    tree_insert(t, 11);
    tree_insert(t, 13);
    tree_insert(t, 9);
    tree_insert(t, 12);
    tree_insert(t, 5);
    tree_insert(t, 2);
    tree_insert(t, 3);


    deleteNodeFromBST(t, 16);
    deleteNodeFromBST(t, 19);
    deleteNodeFromBST(t, 13);
    deleteNodeFromBST(t, 11);



    in_order(t);
    return 0;
}

【问题讨论】:

  • Visual Studio -- 这包括业内最好的调试器之一。为什么不使用它来解决您的问题?

标签: c++ visual-studio function binary-tree binary-search-tree


【解决方案1】:

这段代码:

if (maxLeftValue->left != NULL)
    {
        maxLeftValuePrev->right = maxLeftValue->left;
    }
    else
    {
        maxLeftValuePrev = NULL;
    }

包含两个错误。首先,正如@DrakeWu 指出的,第二个分配不正确;它将一个新值分配给一个不再使用的局部变量,并且树可以留下一个指向已删除节点的指针。其次,第一个赋值假设maxLeftValue 是一个右孩子。如果(可能发生)它是一个左孩子,那么一个节点可以成为两个不同节点的孩子,所以树不再是树了。

这是纠正此代码的一种方法:

if(maxLeftValuePrev->left == maxLeftValue)
    maxLeftValuePrev->left = maxLeftValue->left;
else
    maxLeftValuePrev->right = maxLeftValue->left;

(另外,你的命名约定不好——你不应该给一个节点一个以“Value”结尾的名字。)

【讨论】:

    【解决方案2】:

    更改函数的最后几行:

    void deleteNodeFromBST(BinTreeNode* root_value, int key_value)
    {
        .
        .
        .
        else if (selected_node->left != NULL && selected_node->right != NULL)
        {
             .
             .
             .
    
            if(maxLeftValuePrev->left == maxLeftValue)
                maxLeftValuePrev->left = maxLeftValue->left;
            else
                maxLeftValuePrev->right = maxLeftValue->left;
            delete maxLeftValue;
            maxLeftValue = NULL;
            return;
        }
    }
    

    您的代码中的逻辑是: 如果我们要删除的节点有两个孩子,我们在左子树(子树的最右边节点)中找到最大值并替换它,并删除这个子树最右边的节点--“maxLeftValue”。您应该将 maxLeftValuePrev-right 设置为 NULL 但不是 maxLeftValuePrev

    【讨论】:

    • 我认为你没有测试过这个。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多