我正在尝试用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>
答案 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之类的工具来捕获内存访问问题。在编码时要更加小心,应该首先防止这样的错误。