C中的家谱

时间:2018-04-04 16:10:49

标签: c pointers

我正在编写一个家族树程序,我在从家谱中删除一个节点时遇到了麻烦。我有一个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);
    }
}

3 个答案:

答案 0 :(得分:2)

enter image description here

对不起。

反正,

// 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"可能是更合适的名称,而不是leftright

答案 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*