2017-07-28 26 views
2

我想寫一個代表一棵家族樹作爲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是否也使用指向指針的指針?

+0

'struct NTree_S * next; //指向第一個孩子'和 'struct NTree_S * child; //指向下一個兄弟的指針......我想你在這裏混淆了註釋。 – lurker

+1

你也知道你一直覆蓋你的'line'緩衝區內容,這意味着你會覆蓋你讀入的父母/孩子的名字,對吧?如果你想這樣做,你需要爲每個'fgets'調用分配一個新的行緩衝區。 – lurker

+0

我想覆蓋以前的名字,這樣我就可以每次添加一個新的孩子。我仍然不明白爲什麼根不會改變。 – NULL

回答

0

我改變了這兩個功能帶雙指針:

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

在&根傳遞到add_child正確更新根。

add_child(&root, parent, child); 

謝謝你的幫助。