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

时间:2015-11-17 03:32:00

标签: c pointers recursion binary-search-tree

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

以下是代码:

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

除了&#39; 11&#39;之外的所有内容。不再附加到树上,我相当肯定我的程序中的某些东西正在指定它们不应被分配的指针,并且树节点正在虚空中丢失。有什么想法吗?

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

1 个答案:

答案 0 :(得分:1)

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

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

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

然而你这样做了:

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

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

由于你将&current->left传递给第一个参数,我可以假设它的类型是指向struct TreeNode **rootRef的指针,即struct TreeNode ***rootRef ......

这意味着您要将地址01分配给leftright个节点?这对我来说似乎很奇怪,可能会给你带来麻烦。

注意: 这不是一个解决方案,但它太大了,不适合评论。

既然您选择了递归,请告诉我是否可以帮您解决这个问题......

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;
}

绘制指针图。我发现像thisthis这样的图表对我最有帮助。这并不令人尴尬,它会帮助您理解您所写的内容。重要的是要想象这些事情,特别是当你刚刚学习时。

我试图稍微修改一下代码。我承认我没有花太多时间来尽可能地进行校对,但它应该足以让你对解决方案有所了解。 不要只是复制/粘贴它,我不保证它会起作用。但它应该可以帮助你走上正确的道路。