C - n元树的根没有被保存/更新
问题描述:
我想写一个代表一棵家族树作为n元树的程序。程序必须从CSV文件中读取名称并构建树。树是由下面的结构表示:C - n元树的根没有被保存/更新
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()中?
UPDATE:
我改变了build_tree()声明:
void build_tree(NTree** root, FILE *fp);
我呼吁add_child()像这样:
add_child(root, parent, token); // add child
不过,我仍然有同根问题。每次我打印树时都会发生分段错误,因为根是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: 当从命令行运行,原始根被保存但孩子没有被正确放置。这里有一个例子:
- 命令>添加爸爸,儿子
- 根是空的...
- 命令>打印爸爸
- 爸爸有儿子
- 儿子没有后代。
- 命令>添加儿子,婴儿
- 发现父母
- 父名:儿子
- 错误:孩子已经在树作为父母的孩子。
- 命令>添加随机,随机
- 发现父母
- 父名:随机
- 错误:孩子已经在树作为父母的孩子。
- 命令>打印爸爸
- 爸爸有随机
- 随机没有后代。
爸爸根被保存,但它只会有一个孩子。 add_child_helper是否也使用指向指针的指针?
答
我改变了这两个功能带双指针:
add_sibling(NTree** child, char* sibling);
add_child_helper(NTree** parent, char* child);
在&根传递到add_child正确更新根。
add_child(&root, parent, child);
谢谢你的帮助。
'struct NTree_S * next; //指向第一个孩子'和 'struct NTree_S * child; //指向下一个兄弟的指针......我想你在这里混淆了注释。 – lurker
你也知道你一直覆盖你的'line'缓冲区内容,这意味着你会覆盖你读入的父母/孩子的名字,对吧?如果你想这样做,你需要为每个'fgets'调用分配一个新的行缓冲区。 – lurker
我想覆盖以前的名字,这样我就可以每次添加一个新的孩子。我仍然不明白为什么根不会改变。 – NULL