为BST设置一个递归删除函数,该函数不会将指针归零到叶节点。
bool removeNode(Node* tree, int key)
{
bool removed = false;
if (tree)
{
if (key < tree->key)
{
removeNode(tree->left, key);
}
else if (key > tree->key)
{
removeNode(tree->right, key);
}
else // this node is the key
{
if (!tree->left && !tree->right) // leaf
{
free(tree);
tree = 0;
}
else if (!tree->left)
{
*tree = *tree->right;
}
else if (!tree->right)
{
*tree = *tree->left;
}
else // this node has 2 children
{
Node* paux = tree->left;
if (paux->right)
{
while (paux->right)
{
paux = paux->right;
}
}
tree->key = paux->key;
tree->left = paux->left;
}
removed = true;
}
}
return removed;
}
我用
Node* node = (Node*)malloc(sizeof(Node));
分配内存。我的叶子地址被正确归零,但当它返回上一次呼叫时,地址仍然保持不变。如果地址归零,为什么它会返回到先前的值?这个改变应该影响指针......不应该吗?
数据结构和相关功能:
typedef struct Node
{
int key;
struct Node* left;
struct Node* right;
} Node;
// init a binary tree
void init(Node** tree, int key)
{
*tree = (Node*) malloc(sizeof(Node));
(*tree)->key = key;
(*tree)->left = 0;
(*tree)->right = 0;
}
// insert at binary tree
bool insert(Node** tree, int key)
{
bool inserted = false;
if (!*tree)
{
init(&*tree, key);
}
else
{
Node* node = (Node*)malloc(sizeof(Node));
node->key = key;
node->left = 0;
node->right = 0;
Node* paux = *tree;
Node* root = paux;
while (paux != 0)
{
root = paux;
if (key < paux->key)
{
paux = paux->left;
}
else
{
paux = paux->right;
}
}
paux = node;
if (key < root->key)
{
root->left = paux;
}
else
{
root->right = paux;
}
inserted = true;
}
return inserted;
}
void print(Node* tree)
{
if (tree != 0)
{
printf("%d ", tree->key);
print(tree->left);
print(tree->right);
}
答案 0 :(得分:4)
遇到的问题是因为函数无法修改输入指针。指针本身按值传递。
考虑一个递增整数的函数。这个简单的实现不会起作用,因为参数传递了#34;值#34;。
void inc(int x)
{
x++;
}
您可以通过引用(指针)
来传递此示例void inc(int *x)
{
(*x)++;
}
所以,如果你想能够在函数内使指针无效,则传递一个指向指针的指针:
bool removeNode(Node **tree, int key)
答案 1 :(得分:3)
由于您希望能够在函数内部更改tree
,因此需要双指针。
而不是
bool removeNode(Node* tree, int key)
你需要
bool removeNode(Node** tree, int key)
^^
这也意味着您需要更改在函数内访问tree
的方式。
另见:https://stackoverflow.com/a/39436538/4386427 - 这是同样的问题
答案 2 :(得分:1)
removeNode()
拥有自己的tree
副本,因此在tree
之外无法看到对removeNode()
本身实际值的更改。其中一个选项是将tree
设为Node **
,正如其他人所建议的那样。另一种选择是重构,以便在要释放节点的位置使父节点指针可用。例如,父项可以作为另一个参数传递给removeNode()
,或者您的代码可以在处理时更深入地测试一个级别。然后你可以做free(parent->left); parent->left=0;
或其他一些。