删除叶节点时的二进制搜索树错误

时间:2018-11-16 01:16:55

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

我正在测试从二进制搜索树中删除节点的功能,但是发现我无法删除叶节点。当涉及到打印整棵树时,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;
}

2 个答案:

答案 0 :(得分:0)

更改函数的最后几行:

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

答案 1 :(得分:0)

此代码:

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;

(而且,您的命名约定不好-您不应该给 node 一个以“ Value” 结尾的名称。)