在用C++实现二叉查找树delete操作时出现了奇怪的行为,要被删除掉的节点并没有被删除,而是值变成了0,一番查找确认算法本身没问题,最后发现是向函数传递参数时出现的错误,函数应该接收的是指针引用或者指针的指针,但我的实现接收的是指针的值,先贴正确代码
class TreeNode
{
public:
TreeNode(int v): val(v), left(NULL), right(NULL){}
int val;
TreeNode *left, *right;
};
bool Delete(TreeNode * &root)
{
TreeNode *temp = NULL;
if (!root->left)
{
temp = root;
root = root->right;
delete temp;
temp = NULL;
}
else if (!root->right)
{
temp = root;
root = root->left;
delete temp;
temp = NULL;
}
else
{
temp = root;
TreeNode *cur = root->left;
while (cur->right)
{
cur = cur->right;
}
cur->right = root->right;
root = root->left;
delete temp;
temp = NULL;
}
return true;
}
bool deleteNode(TreeNode * &root, int x)
{
if (!root) return false;
if (root->val == x)
return Delete(root);
else if (root->val > x)
deleteNode(root->left, x);
else
deleteNode(root->right, x);
}
这里使用的删除策略是,当被删除节点 p 的左子树和右子树均不为空时,令 p 的左子树成为 p 父节点的左(右)子树,p 的右子树成为 p 的前驱的右子树,删除 p。用户调用 deleteNode 函数,Delete 应是私有函数,被 deleteNode 调用。
原来错误版本代码与这个版本的唯一不同,就是两个函数的参数列表中都是 TreeNode *root,而不是指针引用。那么区别在哪?当我们把一根指针传递给一个函数,其实也是把指针拷贝了一份副本传递给了函数,与一般的函数传值并无不同,这样做当只是想修改指针指向的对象时并无不妥,但是当要改变指针本身的指向时就会出问题,函数内部做出的修改只是在副本上的修改,而原本的指针仍保留着原来的值。例如下面的例子,它的两次输出均为 “outside”:
void test(string *p)
{
p = new string("inside");
}
int main()
{
string ss = "outside";
string *p = &ss;
cout<< *p<< endl;
test(p);
cout<< *p<< endl;
return 0;
}
若想得到想要的 “outside”,“inside” 输出,最简单的方法就是改成 void test(string * &p),这样内部代码无需改动就可实现功能。或者使用指针的指针,如下:
void test(string **p)
{
*p = new string("inside");
}
int main()
{
string ss = "outside";
string *p = &ss;
cout<< *p<< endl;
test(&p);
cout<< *p<< endl;
return 0;
}
本文通过一个二叉查找树删除节点的例子,探讨了在C++中使用指针引用的必要性。错误地传递指针值导致删除操作失败,正确做法是传递指针引用或指针的指针。文中详细解释了为何传递指针副本无法修改原始指针,并提供了修改方法。
483

被折叠的 条评论
为什么被折叠?



