当前位置: 首页 > 知识库问答 >
问题:

删除二进制搜索树中的节点-C

冯渝
2023-03-14

我目前正在做一个学校项目,我必须为二叉搜索树编写一些辅助函数。其中一个函数从树中删除了一个节点。我正在尝试运行一些测试用例,但似乎无法让它们正常工作。我知道这个问题与我如何使用指针有关,但我不太确定我哪里出错了。

这是代码:

int removeBST (struct TreeNode **rootRef, int data)
{
    struct TreeNode *current = *rootRef;
    struct TreeNode *temp = current;

    if (current == NULL)
        return 0;

    if (data < current->data) 
    {
        current->left = removeBST (&current->left, data);
    }

    if (data > current->data) 
    {
        current->right = removeBST (&current->right, data);
    }

    if (current->left == NULL || current->right == NULL)
        return 0;
    else 
    {
        if (current->left == NULL) {
            temp = current->right;
            current = temp;
            free (temp);
            return 1;
        } 
        else if (current->right == NULL) {
            temp = current->left;
            current = temp;
            free (temp);
            return 1;
        }
        temp = leftRoot (current->right);
        current->data = temp->data;
        current->right = removeBST (&current->right, temp->data);

    }

    return 1;
}

注意:我没有包括leftRoot()函数,但它相当简单,我知道它做了它应该做的事情(返回子树中最左边的根)下面是我的教授给我们的测试remove函数的代码部分:

  for(i = -4; i < 25; i+=4)
  {
    n = removeBST(&bst, i);
    if(!n) printf("remove did not find %d\n", i);
  }

如果有必要,下面是创建树并插入数据的整个测试代码:

struct TreeNode* bst = NULL;
for(i = 0; i < 23; ++i)
  {
    n = (i*17+11) % 23;
    bst = insertBST(bst, n);
  }

  printf("filled BST: ");
  printTree(bst);
  printf("BST leaves: ");
  printLeaves(bst);
  printf("BST depth = %d\n", maxDepth(bst));
  printf("BST minimum value = %d\n", minValueBST(bst));
  printf("BST isBST = %d\n", isBST(bst));

  for(i = -4; i < 25; i+=4)
  {
    n = removeBST(&bst, i);
    if(!n) printf("remove did not find %d\n", i);  
  }

整个输出是:

filled BST: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 
BST leaves: 0 6 12 17 
BST depth = 8
BST minimum value = 0
BST isBST = 1
remove did not find -4
remove did not find 0
remove did not find 4
(this part repeats all the way up to 24)
BST after removes: 11

由于除了“11”之外的所有内容都不再附加到树,我相当确定我的程序中的某些内容正在分配不应该分配的指针,并且树节点只是在空白中丢失了。有什么想法吗?

编辑:我忘记提供一条信息,被删除节点最左边的子节点应该替换被删除的节点。

共有1个答案

秦涵涤
2023-03-14

我不确定我是否发现了您代码中的所有问题,但这里有一个主要问题:

int removeBST (struct TreeNode **rootRef, int data)

您的函数返回一个int,并由许多返回1返回0语句证实...

然而你却做到了:

    if (data < current->data) 
    {
        current->left = removeBST (&current->left, data);
    }

    if (data > current->data) 
    {
        current->right = removeBST (&current->right, data);
    }

既然你通过了

这意味着您正在将地址分配给左节点和右节点?这对我来说似乎很奇怪,可能会给你带来问题。

注意:这不是一个解决方案,但它太大,无法放入注释中。

既然你选择了递归,让我看看我是否能帮你解决这个问题...

int removeBST (struct TreeNode **rootRef, int data)
{
    struct TreeNode *current = *rootRef;
    struct TreeNode *temp = current;

    if (current == NULL)
        return 0;

    if (data < current->data) 
    {
        // We don't want to modify things here, just let the next 
        // call take care of it and return what it returns.
        return removeBST(&current->left, data);
    }
    else if (data > current->data) 
    {
        // Same here.
        return removeBST(&current->right, data);
    }
    else 
    {
        if (current->left == NULL) {
            temp = current->right;
            // The rest of the stuff from here moved below.
            // Because I added the else, the return isn't needed 
            // here anymore either, since the one at the bottom 
            // will return 1 anyway.
        } 
        else if (current->right == NULL) {
            temp = current->left;
            // I did the same here.
        }
        else {
            temp = leftRoot (current->right);
            // This was on the outside but really it should be an else 
            // since it means less code...
            // Additionally, once you got the left root why did you decide
            // to remove it too? As far as I can see you only want to 
            // remove this one... If not, then you might have some work 
            // to do here...
        }

        *rootRef = temp; // current and rootRef are not the same. 
                         // You need to use rootRef here so that we 
                         // move the temp pointer to the current one 
                         // (replace it). Think carefully about where 
                         // the pointers are! Pointers also have addresses 
                         // and it matters what address you write to 
                         // where, use pen and paper and draw where things 
                         // point! 
        free (current);  // this means that we can't delete temp! so 
                         // since, we've just deleted the "current" 
                         // pointer we should discard it too...
    }

    return 1;
}

为指针绘制图表。我发现这样或这样的图表对我帮助最大。这并不令人尴尬,它会帮助你理解你在写什么。将这些东西形象化是很重要的,尤其是在你刚刚学习的时候。

我试着把代码修改一下。我承认我没有花尽可能多的时间进行校对,但应该可以给你一个解决方案的想法。不要只是复制/粘贴这个,我不能保证它会起作用。但这应该会帮助你走上正确的道路。

 类似资料:
  • 目前,我在理解如何在没有传递节点时从二进制搜索树中删除节点时遇到了一个问题。我有两个类,BSTSet和BSTNode,每个类都有一个remove方法。。 当我被传递一个节点时,我理解删除方法,但当我在根上调用remove方法并试图从node类中删除节点时,我不知道从何处开始。有人能告诉我吗?谢谢如果您想了解更多信息,请询问。

  • 我正在尝试删除我的二叉查找树的根,以便我可以更新它的值,但这种方法不能做到这一点。我的想法是删除根,然后将其再次插入二叉查找树中,但使用另一个值。它适用于树中的每个节点,但不是我无法删除它的根本原因。有人知道为什么会发生这种情况吗?谢谢。 这是我调用方法删除任何节点的主代码,在这种情况下,我想删除根。

  • 我正在尝试从二叉查找树中删除节点。我可以成功地删除树上的任何其他节点,除了一个特殊的情况。如果目标节点有两个子节点,左边的子节点有右边的子树,我可以定位正确的替换节点,并将值切换到目标节点,但替换节点永远不会被删除。 看看上面的图片,如果我尝试删除17,程序将正确地导航到13,并用13替换17,但它不会像预期的那样删除原来的13。 我附加了我的remove方法和其中引用的方法。 这是我的Node类

  • 我试着删除二叉查找树的节点,当我打印出来的时候,我得到的结果实际上不是这个删除,实际上可以删除二叉树本身的任何键。 我是二进制搜索树的新手。有人能帮我写代码吗?我们将感谢您的帮助。 谢谢 完整代码

  • 主要内容:src/runoob/binary/BSTRemove.java 文件代码:本小节介绍二分搜索树节点的删除之前,先介绍如何查找最小值和最大值,以及删除最小值和最大值。 以最小值为例(最大值同理): 查找最小 key 值代码逻辑,往左子节点递归查找下去: ... // 返回以node为根的二分搜索树的最小键值所在的节点 private Node minimum (Node node ) {     if ( node. left == null )         retu

  • 我在C中实现了一个二进制搜索树。 对于delete方法,除了最后一种情况外,其他情况都可以使用,即唯一的树是父树,并且它指向两个空的子树。现在的问题是:我希望在删除子树后,打印出父树的左子树和右子树等于什么。它们和父项都应该为NULL,但是当我试图输出这些值时,我得到了一个状态访问冲突。 下面是有关删除的代码。我希望删除父节点,并设置树- 主要: