我目前正在开展一个学校项目,我必须为二元搜索树编写一些辅助函数。其中一个函数从树中删除节点。我试图运行一些测试用例,但我似乎无法让它们工作。我知道问题与我如何使用指针有关,但我不太确定我哪里出错了。
以下是代码:
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 (¤t->left, data);
}
if (data > current->data)
{
current->right = removeBST (¤t->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 (¤t->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;之外的所有内容。不再附加到树上,我相当肯定我的程序中的某些东西正在指定它们不应被分配的指针,并且树节点正在虚空中丢失。有什么想法吗?
编辑:我忘记提供的一条信息,删除的节点的最左边的孩子应该替换已删除的节点。答案 0 :(得分:1)
我不确定我是否在代码中发现了所有问题,但这里有一个主要问题:
int removeBST (struct TreeNode **rootRef, int data)
您的函数返回int
,由多个return 1
或return 0
语句证实......
然而你这样做了:
if (data < current->data)
{
current->left = removeBST (¤t->left, data);
}
if (data > current->data)
{
current->right = removeBST (¤t->right, data);
}
由于你将¤t->left
传递给第一个参数,我可以假设它的类型是指向struct TreeNode **rootRef
的指针,即struct TreeNode ***rootRef
......
这意味着您要将地址0
和1
分配给left
和right
个节点?这对我来说似乎很奇怪,可能会给你带来麻烦。
注意: 这不是一个解决方案,但它太大了,不适合评论。
既然您选择了递归,请告诉我是否可以帮您解决这个问题......
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(¤t->left, data);
}
else if (data > current->data)
{
// Same here.
return removeBST(¤t->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;
}
绘制指针图。我发现像this或this这样的图表对我最有帮助。这并不令人尴尬,它会帮助您理解您所写的内容。重要的是要想象这些事情,特别是当你刚刚学习时。
我试图稍微修改一下代码。我承认我没有花太多时间来尽可能地进行校对,但它应该足以让你对解决方案有所了解。 不要只是复制/粘贴它,我不保证它会起作用。但它应该可以帮助你走上正确的道路。