在c中建立一棵nary树

时间:2016-12-09 10:03:52

标签: c recursion

我正在尝试用C创建一个n-ary树。我遇到了递归填充树的问题。我希望你能帮忙。

实现取决于已经过测试和工作的两个函数insert_child和append_child。

我试图以递归方式构建一棵nary树。通过将子项追加并插入到main中创建的根节点来手动构建它。如上所述,如果节点中已存在子节点,则取决于insert_child(),如果节点中没有现有子节点,则取决于append_child()。

它目前从未停止运行,并且不会输出1表示成功。

整个计划:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_LINE_SIZE 85
#define MAX_NODES 50
#define MAX_CHILDREN 5

// Data
typedef struct {
  int library_choice;
  double probability;
  int child_id; // unique id from 1-n (total)
  int child_index; // index from left in node from 1-n
  int kr; // Antal Kr. Kun available in some cases
  int utility; // Kun available in if Leafnode
} d_child;

typedef struct {
  int node_index; // From 1-n for each level (resets)
  int node_id; // unique id from 1-n (total)
  int n_children; // Number of children in level
  d_child d_child[MAX_CHILDREN];
} d_node;

typedef struct {
  int level_id; // From 1-n
  int player; // From 1-n
  int n_nodes; // From 1-n
  d_node d_node[MAX_NODES];
} d_level;

// Tree
typedef struct s_nary_node {
  d_level data; // nodes data -> comes in index for the level
  int n; // the number of children
  struct s_nary_node **child; // the child list
} nary_node;
typedef nary_node nary_tree;

nary_tree *create_node(int children, d_level *data, int i) {
  // allocate space for new nary_node
  nary_node *node = (nary_node*)calloc(1, sizeof(nary_node));

  // Set the contents of the NODE
  node->data = data[i];
  node->n = children;
  node->child = (nary_node**)calloc(children, sizeof(nary_node*));

  return node;
}

int append_child(nary_node *root, d_level *data, int i) {
  // Increment the degree of the node
  root->n++;

  // Reallocate the child array (n children in the child array)
  root->child = (nary_node **)realloc(root->child,(root->n)*sizeof(nary_node*));

  // Add the newNode into the child array and increment degree
  root->child[root->n - 1] = create_node(0, data, i);

  // Return the index of the child we just inserted
  return root->n - 1;
}

int insert_child(nary_node *root, int idx, d_level *data, int i) {
  int j;

  // First we make space
  root->n++;
  root->child = (nary_node**)realloc(root->child, (root->n)*sizeof(nary_node*));
  for(j=root->n-1; j>idx; --j) 
    root->child[j] = root->child[j-1];
  root->child[j] = create_node(0, data, i);
  return j;
}

int create_tree(nary_node *root, d_level *data, int i) {
  int j = 1;

  if(root->n == 0) return 0; // Terminating condition
  else {
    for(j=1; j<root->n+1; j++) { // For every nodes children
      printf("Hey\n");
      if(root->child[j] == NULL) {
        append_child(root, data, i);
      }
      else { 
        insert_child(root, j, data, i);
      }
      i++; // Count up level for data
      root = root->child[j];
      create_tree(root, data, i);
    }
    return 1;

  } 
}

// Data
int count_levels() {
  int count = 0;
  FILE *input_file; 
  input_file = fopen("data.xml", "r"); 
  if(input_file == NULL) { printf("Could not open file\n"); }
  else {
    char temp[MAX_LINE_SIZE]; 
    char level[] = "<level";
    while(fgets(temp, MAX_LINE_SIZE, input_file)!= NULL) {
      if(strstr(temp, level) != NULL) {
        count++;
      }
    }
  }
  return count;
}

void read_level_data(d_level *d_level){
  char temp[MAX_LINE_SIZE];
  char level[] = "<level";
  int i = 1;

  // Opening file
  FILE *input_file; 
  input_file = fopen("data.xml", "r"); 

  if(input_file == NULL) { printf("Could not open file\n"); }
  else {
    while(fgets(temp, MAX_LINE_SIZE, input_file)!= NULL){
      if(strstr(temp, level)) {
        sscanf(temp, "<level id=\"%d\" player=\"%d\"  nNodes=\"%d\">", &d_level[i].level_id, &d_level[i].player, &d_level[i].n_nodes);
        i++;
      }
    }
  }
}

void read_node_data(d_level *d_level){
  char temp[MAX_LINE_SIZE];
  char node[] = "<node";
  char end_node[] = "</node";
  char end_level[] = "</level>";

  int i = 1;
  int j = 1;
  // Opening file
  FILE *input_file; 
  input_file = fopen("data.xml", "r"); 

  if(input_file == NULL) { printf("Could not open file\n"); }
  else {
    while(fgets(temp, MAX_LINE_SIZE, input_file)!= NULL){
      if(strstr(temp, node)) {
        sscanf(temp, " <node idx=\"%d\" id=\"%d\" nChildren=\"%d\">", &d_level[i].d_node[j].node_index, &d_level[i].d_node[j].node_id, &d_level[i].d_node[j].n_children);
      } 
      else if(strstr(temp, end_node)) {
        j++;
      }
      else if(strstr(temp, end_level)) {
        i++;
        j = 1; // reset nodecount for each iteration
      }
    }
  }
}

void read_child_data(d_level *d_level){
  char temp[MAX_LINE_SIZE];
  char child[] = "<child";
  char library_choice[] ="<libraryChoice";
  char probability[] = "<probability";
  char utility[] = "<probability";
  char kr[] = "<kr";
  char end_child[] = "</child";
  char end_node[] = "</node";
  char end_level[] = "</level";

  int i = 1;
  int j = 1;
  int k = 1;

  // Opening file
  FILE *input_file; 
  input_file = fopen("data.xml", "r"); 

  if(input_file == NULL) { printf("Could not open file\n"); }
  else {
    while(fgets(temp, MAX_LINE_SIZE, input_file)!= NULL){
      if(strstr(temp, child)) {
        sscanf(temp, " <child idx=\"%d\" id=\"%d\">", &d_level[i].d_node[j].d_child[k].child_index, &d_level[i].d_node[j].d_child[k].child_id);
      } 
      else if(strstr(temp,library_choice)) {
        sscanf(temp, " <libraryChoice>%d</libraryChoice>", &d_level[i].d_node[j].d_child[k].library_choice);
      } 
      else if(strstr(temp,probability)) {
        sscanf(temp, " <probability>%lf</probability>", &d_level[i].d_node[j].d_child[k].probability);
      } 
      else if(strstr(temp,utility)) {
        sscanf(temp, " <utility>%d</utility>", &d_level[i].d_node[j].d_child[k].utility);
      } 
      else if(strstr(temp,kr)) {
        sscanf(temp, " <kr>%d</kr>", &d_level[i].d_node[j].d_child[k].kr);
      }
      else if(strstr(temp, end_child)) { // </child
        k++;
      }
      else if(strstr(temp, end_node)) { // </node
        j++;
        k = 1;
      } 
      else if(strstr(temp, end_level)) { // </level
        i++;
        j = 1;
      }
    }
  }
}

int main(void) {
  // Data
  d_level *d_level =  calloc(count_levels(), sizeof(1, d_level));

  // Read level data
  read_level_data(d_level);

  // Read node data
  read_node_data(d_level);

  // Read children data
  read_child_data(d_level);

  int i = 1; 
  nary_tree* root = (nary_node*)calloc(count_levels(),sizeof(nary_node));
  root = create_node(2, d_level, i);
  nary_tree* temp = (nary_node*)calloc(count_levels(),sizeof(nary_node));
  temp = root;
  int success = create_tree(temp, d_level, i);
  printf("Return value: %d\n", success);
}

我正在解析的XML输入:

<level id="1" player="1" nNodes="1">
  <node idx="1" id="1" nChildren="2">
    <child idx="1" id="1">
      <libraryChoice>1</libraryChoice>
      <kr>1000</kr>
    </child>
    <child idx="2" id="2">
      <libraryChoice>2</libraryChoice>
      <kr>2000</kr>
    </child>
  </node>
</level>

<level id="2" player="2" nNodes="2">
<node idx="1" id="2" nChildren="2">
<child idx="1" id="3">
  <libraryChoice>1</libraryChoice>
  <probability>50.0</probability>
</child>
<child idx="2" id="4">
  <libraryChoice>2</libraryChoice>
  <probability>50.0</probability>
</child>
</node>
<node idx="2" id="3" nChildren="2">
<child idx="1" id="5">
  <libraryChoice>3</libraryChoice>
  <probability>50.0</probability>
  <utility>-100</utility>
  <kr>3000</kr>
</child>
<child idx="2" id="6">
  <libraryChoice>4</libraryChoice>
  <probability>50.0</probability>
  <utility>100</utility>
  <kr>4000</kr>
</child>
</node>
</level>

<level id="3" player="1" nNodes="2">
<node idx="1" id="4" nChildren="0">
</node>
<node idx="2" id="5" nChildren="0">
</node>
<node idx="3" id="6" nChildren="0">
</node>
<node idx="4" id="7" nChildren="0">
</node>
</level>

1 个答案:

答案 0 :(得分:1)

main()

d_level *d_level =  calloc(count_levels(), sizeof(1, d_level));

sizeof的论点在这里是错误的。让我们忽略&#34; 1,&#34;首先,它没有做任何事情。使用sizeof(d_level),您可能需要获得struct d_level的大小。但是,您已将其重新声明为d_level *类型的变量。所以sizeof(d_level)这里将返回指针的大小,而不是struct的大小。做得更好:

d_level *d_level = calloc(count_levels(), sizeof *d_level);

下一个问题出在read_level_data()

int i = 1;
...
while(fgets(temp, MAX_LINE_SIZE, input_file)!= NULL){
  if(strstr(temp, level)) {
    printf("%i\n", i);
    sscanf(temp, "<level id=\"%d\" player=\"%d\" nNodes=\"%d\">", &d_level[i].level_id, &d_level[i].player, &d_level[i].n_nodes);
    i++;
  }
}

您在1处开始索引i。但是,在C中,数组从0开始计数。请改用int i = 0。你在其他功能中犯了同样的错误。

然后有create_tree()。它以递归方式调用自身。但是,在这两行中:

  root = root->child[j];
  create_tree(root, data, i);

root->child[j]可能会发生NULL,这意味着您使用NULL指针调用create_tree(),从而导致分段错误。此外,您正在修改变量root,这可能不是您想要的。做得更好:

  if(root->child[j])
    create_tree(root->child[j], data, i);

此后还有更多问题。

在启用警告的情况下编译代码,并修复您首先发现的任何警告。然后,使用调试器分析分段错误,或使用valgrind之类的工具来捕获内存访问问题。在编码时要更加小心,应该首先防止这样的错误。