更改树的根和修剪

时间:2017-09-13 15:46:46

标签: c recursion tree

我有一个n-ary树结构,就像答案here中解释的那样:

typedef struct node {
    int ID;
    struct node *child;   // points to (first) child
    struct node *next;    // points to next node at same level (sibling)
    struct node *parent;  // points to parent
} node;

使用malloc创建节点。

我想编写一个函数,将树的根更改为另一个(指定的)节点,并释放所有节点的内存 - 由于根的更改 - 不再是树的一部分(即如果某个节点无法通过父节点追溯到新根节点,则应将其设置为NULL并释放其内存。

例如,如果这是我的树:

      1           
     / \
    2   3        
   / \    \
  4  5     6      
 / \
7   8     

我希望将根目录从1更改为3,然后在调用prune_tree函数后,root将为3,并且除了3和6之外的每个节点的内存都将被释放。

我最接近解决问题涉及此功能:

void prune_tree(node **root, node *new_root) {
    if (*root == NULL || (*root)->parent == new_root)
        return;

    prune_tree(&((*root)->child), new_root);
    prune_tree(&((*root)->next), new_root);

    free(*root);
    *root = NULL;
}

并在调用此函数后设置

root = new_root;

我主要通过反复试验来到这里;事实上,我甚至不确定为什么在我测试它的大部分时间都能正常工作。它还添加了在调用函数后必须将根设置为新根地址的不必要步骤。我假设我可以修改函数中的根地址,或者返回新的根地址。

我认为我不需要担心内存使用,因为该函数正在释放内存,但最好是节省时间的函数。我不确定这是否意味着我应该避开递归......

3 个答案:

答案 0 :(得分:0)

您的方法不起作用,因为您将释放新根本身。您只能在parent是新根的节点上停止。

以下是更正后的版本:

void prune_tree(node **root, node *new_root) {
    if (*root == NULL)
        return;
    if (*root == new_root) {
        (*root)->parent = NULL;
        return;
    }
    prune_tree(&(*root)->child, new_root);
    prune_tree(&(*root)->next, new_root);
    free(*root);
    *root = NULL;
}

在使用地址调用此函数后,您仍需要将树的根更新为new_root

prune_tree(&root, new_root);
root = new_root;

答案 1 :(得分:0)

递归函数对此非常完美。

你基本上想要做什么(假设树中没有循环)是删除新根的所有兄弟,包括他们的孩子和父母以及根的父母。

算法可以是:

typedef struct node {
    int ID;
    struct node *child;
    struct node *sibling;
    struct node *parent;
} node;

void remove_node(struct node* node, struct node* root)
{
    if(node->parent != NULL)
        remove_node(node->parent, new_root)

    if(node->sibling != NULL)
        remove_node(node->sibling, new_root)

    if((node->child != NULL) && (node->child != root))
        remove_node(node->sibling, new_root)

    free(node)
}

void prune_tree(node **root, node *new_root) {
    *root = new_root
    remove_node(new_root->parent);
    remove_node(new_root->sibling);
}

假设:

  • new_root在树中
  • 树中没有循环

答案 2 :(得分:0)

我想我找到了解决方案......

void prune_tree(node** root, node* new_root)
{
    bool del = true;

    if (*root == NULL)
        return;

    if (*root == new_root) {
        del = false;
    }

    if (del){
        prune_tree(&(*root)->child, new_root);
        prune_tree(&(*root)->next, new_root);
        free(*root);
        *root = NULL;
    }
    else{
        prune_tree(&(*root)->next, new_root);
    }
}