【问题标题】:C - Root of n-ary tree not being saved/updatedC - n-ary 树的根没有被保存/更新
【发布时间】:2018-01-05 03:17:06
【问题描述】:

我正在尝试编写一个将家谱表示为 n 叉树的程序。程序必须从 CSV 文件中读取名称并构建树。树由以下结构表示:

typedef
   struct NTree_S {
      char * name; // name of the person
      struct NTree_S *next; // pointer to first child
      struct NTree_S *child; // pointer to next sibling 
   } NTree;

当使用硬编码值时,程序构建树和更新根没有问题。

// CASE #4 //
    printf("%s\n", "Entered CASE #4");
    NTree *root4 = NULL;
    root4 = add_child(root4, "Dad", "Son");
    root4 = add_child(root4, "Son", "Baby");
    print_tree(root4, root4->name);

输出:

Entered CASE #4
Dad had Son
Son had Baby
Baby had no offspring.

但是,当使用 build_tree() 函数时,程序不会保存根目录。

NTree * build_tree( FILE *fp) {
    NTree* root = NULL;
    char line[1024]; // max length of any line in an input file 
    while(fgets(line, sizeof(line), fp) != NULL) {
        char *token = strtok(line, ",");
        char *parent = token; // save first token as parent
        while(token != NULL) {
            token = strtok(NULL, ","); // get next token
            root = add_child(root, parent, token); // add child
            if(root == NULL) {
                printf("%s\n", "root is NULL");
            }
        }
    }
    return root; // built tree 
}

该函数获取要添加的正确父项和令牌(子项),但始终打印树为 NULL。我不确定为什么没有保存和更新根。由于工作硬编码的示例,我犹豫是否要更改我的实现以使用指向指针的指针。为什么在硬编码示例中更新并保存了根目录而不是在 build_tree() 中?

更新

我更改了 build_tree() 声明:

void build_tree(NTree** root, FILE *fp);

我这样调用 add_child():

add_child(root, parent, token); // add child

但是,我仍然遇到与 root 相同的问题。每次我打印树时都会发生分段错误,因为根为 NULL。有人可以就我的 add_child 函数给我反馈吗?

void add_child(NTree **tree, char* parent, char* child) {
        NTree *add = create_node(child); // node to add
        if(*tree == NULL) { // tree is empty
            *tree = create_node(parent); // add parent as the root 
            (*tree)->child = add;
            return;
        }
        NTree *found = find_node(*tree, parent); // search tree for parent
        if(found != NULL) { // found parent
            printf("%s\n", "found parent");
            NTree *found2 = find_node(found, child); // search parent tree 
            if(found2 == NULL) { // child not already in tree
                found =add_child_helper(found, child); // add child 
                return;
            } else {
                // error
                return;
            }
        } else { // parent not found
            int cmp = strcmp((*tree)->name, child); // child is root
            if(cmp == 0) {
                NTree *newroot = create_node(parent); // new root
                newroot->child = *tree;
                return;
            } else {
                // error 
                return;
            }
        }
    }
    return;
}

NTree * add_child_helper(NTree *parent, char* child) {
    if(parent->child) { // parent already has child
        return add_sibling(parent->child, child);
    } else {
        parent->child = create_node(child); // make child
        return parent;
    }
    }

NTree * add_sibling(NTree *child, char* sibling) {
    while(child->next) { // find last sibling
        child = child->next;
    }
    child->next = create_node(sibling); // add the sibling
    return child;
}

更新 2: 从命令行运行时,将保存原始根目录,但未正确放置子节点。这是一个例子:

  • command>添加爸爸,儿子
  • root 为空...
  • command>打印爸爸
  • 爸爸有儿子
  • 儿子没有后代。
  • command>添加儿子,宝贝
  • 找到父母
  • 父母姓名:儿子
  • 错误:孩子已经作为父母的孩子在树中。
  • command>添加随机,随机
  • 找到父母
  • 父名:随机
  • 错误:孩子已经作为父母的孩子在树中。
  • command>打印爸爸
  • 爸爸随意
  • 随机没有后代。

爸爸根被保存,但它只会有一个孩子。 add_child_helper 也应该使用指向指针的指针吗?

【问题讨论】:

  • struct NTree_S *next; // pointer to first childstruct NTree_S *child; // pointer to next sibling ...我认为您在这里混淆了 cmets。
  • 您还知道您一直在覆盖您的line 缓冲区内容,这意味着您将覆盖您之前读入的父/子名称,对吧?如果你想这样做,你需要为每个fgets 调用分配一个新的行缓冲区。
  • 我想覆盖以前的名字,这样我每次都可以添加一个新的孩子。我仍然不明白为什么根没有改变。
  • @NULL:您将根指针本身传递给add_child();本质上,add_child() 在根指针的副本上工作。因此,当它修改其副本时,修改仅在 add_child() 函数中可见。要解决此问题,add_child() 函数必须采用 指向根指针的指针,即void add_child(NTree **root, const char *parent, const char *child),以便更改根变为(*root) = new_root,这在调用者中也是可见的。
  • @NominalAnimal 你有机会看看我更新的 add_child 函数吗?

标签: c csv null binary-tree root


【解决方案1】:

我将这两个函数都更改为采用双指针:

add_sibling(NTree** child, char* sibling);
add_child_helper(NTree** parent, char* child);

将 &root 传递给 add_child 正确更新了根目录。

add_child(&root, parent, child);

感谢您的帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-02
    • 1970-01-01
    • 1970-01-01
    • 2014-04-18
    • 2012-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多