我正在编写一个家族树程序,我在从家谱中删除一个节点时遇到了麻烦。我有一个delete
方法,它将要删除的节点的名称,找到它,然后删除它。我释放了trash
节点,我正在尝试删除的节点,并将其设置为NULL
,但是当我测试它时它仍然存在。我是否应该为节点分配新的左右路径,而不是尝试将其设置为NULL
?
struct node {
char *data;
struct node *left;
struct node *right;
}*child;
void delete(node* root){
char array[13];
node *toDelete;
printf ("Please specify a name to delete\n");
scanf("%s", array);
toDelete = scan(root, array);
if(toDelete == NULL) {
printf("ERROR -- Node does not exist");
} else {
removeChild(&toDelete);
}
}
void removeChild(node **trash){
if((*trash)->left == NULL && (*trash)->right == NULL) { //no parents
free(*trash);
*trash = NULL;
}
else if((*trash)->left == NULL && (*trash)->right != NULL) { //have mother
removeChild((*trash)->right);
}
else if((*trash)->left != NULL && (*trash)->right == NULL) { //have father
removeChild((*trash)->left);
} else{ //have both
removeChild((*trash)->left);
removeChild((*trash)->right);
}
}
答案 0 :(得分:2)
对不起。
反正,
// free a node and all its children.
// Return # of nodes freed.
int free_node_recursive(node * n){
int total_freed = 1;
// free the left child (if any)
if(n->left != NULL){
free_node_data(n->left);
total_freed += free_node_recursive(n->left);
n->left = NULL;
}
// free the right child (if any)
if(n->right != NULL){
free_node_data(n->right);
total_freed += free_node_recursive(n->right);
n->right = NULL;
}
// actually free the thing.
free(n);
return total_freed;
}
EG。
void delete(node* root){
char array[13];
node *toDelete;
printf ("Please specify a name to delete\n");
scanf("%s", array);
toDelete = scan(root, array);
if(toDelete == NULL) {
printf("ERROR -- Node does not exist");
} else {
free_node_recursive(&toDelete);
}
}
您的问题是,在全局树(root
)中,对刚删除的节点的引用仍将存在。降序树的解析器会发现父级中的引用仍然完好无损,并尝试进入它,找到已经free
'且无法访问的数据;段错误。
答案 1 :(得分:1)
您对removeChild()
的递归调用已被破坏;它们应包含对left
/ right
的引用;编译应警告它。但是更简单的实现将是
void removeChild(node **trash)
{
if (!*trash)
return;
removeChild(&(*trash)->right);
removeChild(&(*trash)->left);
free(*trash);
*thrash = NULL;
}
但是free()
可能对你的家庭树而言是错误的"节点可以是多个子节点的父节点。你可以在这里实现一些引用计数。
node *toDelete;
...
toDelete = scan(root, array);
...
removeChild(&toDelete);
也需要更改:scan()
应返回node **
,以便&root
可以传递给removeChild()
(当它与array
匹配时)。
而且," mother
"和" father
"可能是更合适的名称,而不是left
和right
。
答案 2 :(得分:1)
以下是我的解决方案:
void delete(node* root){
......
node** toDelete;
toDelete = scan(root, array);
if(toDelete == NULL) {
printf("ERROR -- Node does not exist");
} else {
removeChild(*toDelete);
*toDelete = NULL;
}
}
void removeChild(struct node *trash){
if(trash->left != NULL) {
removeChild(trash->left);
// no need to write trash->left = NULL here,
// as the whole subtree would be removed after all done.
}
if(trash->right != NULL) {
removeChild(trash->right);
}
free(trash);
}
提醒您,scan
必须返回node**
而不是node*
。