Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C使用结构指针递归构建树_C_Pointers_Recursion_Tree_Structure - Fatal编程技术网

C使用结构指针递归构建树

C使用结构指针递归构建树,c,pointers,recursion,tree,structure,C,Pointers,Recursion,Tree,Structure,我现在正在实现模拟N体问题。我只想问一下建筑树的部分 我做了两个函数来为它构建树 我递归地构建树,并在构建时打印每个节点的数据,一切看起来都是正确的,但当程序返回到主函数时,只有树的根和根的子节点存储值。其他节点的值没有被存储,这很奇怪,因为我在递归期间打印了它们,它们应该被存储 下面是经过修改的部分代码,我认为这可能是问题所在: #include<...> typedef struct node{ int data; struct node *child1,*chi

我现在正在实现模拟N体问题。我只想问一下建筑树的部分

我做了两个函数来为它构建树

我递归地构建树,并在构建时打印每个节点的数据,一切看起来都是正确的,但当程序返回到主函数时,只有树的根和根的子节点存储值。其他节点的值没有被存储,这很奇怪,因为我在递归期间打印了它们,它们应该被存储

下面是经过修改的部分代码,我认为这可能是问题所在:

#include<...>
typedef struct node{
    int data;
    struct node *child1,*child2;
}Node;
Node root; // a global variable
int main(){
    .
    set_root_and_build(); // is called not only once cuz it's actually in a loop
    traverse(&root);
    .
}
并建立:

void build(Node *n,...){
    Node *new1, *new2 ;
    new1 = (Node*)malloc(sizeof(Node));
    new2 = (Node*)malloc(sizeof(Node));
    ... // (set data of new1 and new2 **,also their children are set NULL**)
    if(some condition holds for child1){ // else no link, so n->child1 should be NULL
        build(new1,...);
        n->child1 = new1;
        //for debugging, print data of n->child1 & and->child2
    }
    if(some condition holds for child2){ // else no link, so n->child2 should be NULL
        build(new2,...);
        n->child1 = new2;
        //for debugging, print data of n->child1 & and->child2
    }
}
树中的节点可能有1~2个子节点,但并非所有节点都有2个子节点

当程序在
build()
函数递归中时,它会打印出正确的数据,但当它返回到主函数并调用
traverse()
时,由于分段错误,它会失败

我试图在
traverse()
中打印所有内容,发现只有root和root.child1、root.child2存储了我刚才提到的值

由于我必须多次调用
build()
,即使是并行调用,new1和new2也不能定义为全局变量。(但我不认为这是他们造成的问题)

有人知道哪里出了问题吗

包含调试信息的遍历部件:

void traverse(Node n){
    ...//print out data of n
    if(n.child1!=NULL)
        traverse(*(n.child1))
    ...//same for child2
}

当条件不成立时,您可能没有正确设置
n
的子项。您可能需要这样做:

void set_root_and_build()
{
    root.data = ...;
    build(&root,...); // ... part are values of data for it's child 
}

void build(Node *n,...)
{
    n->child1 = n->child2 = NULL;

    Node *new1, *new2;
    new1 = (Node*) malloc(sizeof(Node));
    new2 = (Node*) malloc(sizeof(Node));

    // set data of new1 and new2 somehow (read from stdin?)

    if (some condition holds for new1) 
    {
        n->child1 = new1;
        build(n->child1,...);
        //for debugging, print data of n->child1
    }
    else
      free(new1);  // or whatever else you need to do to reclaim new1

    if (some condition holds for new2)
    {
        n->child2 = new2; 
        build(n->child2,...);
        //for debugging, print data of n->child2
    }
    else
      free(new2);  // or whatever else you need to do to reclaim new2
}
当然,您应该检查malloc()的返回值并处理错误

另外,您的遍历有点奇怪,因为它是通过复制而不是引用递归的。你有理由这么做吗?如果没有,那么您可能需要:

void traverse(Node *n)
{
    ...//print out data of n
    if (n->child1 != NULL)
        traverse(n->child1)
    ...//same for child2
}

树遍历中的问题是,您肯定会处理树,直到找到一个空的节点指针

不幸的是,当您创建节点时,这些节点既没有用
malloc()
初始化,也没有用
new
初始化(它将用
calloc()
初始化,但cpp代码中的这种做法与
malloc()
一样糟糕)。因此,您的遍历将继续在随机指针的梦幻岛中循环/递归

我建议您利用cpp,稍微改变您的结构,以:

struct Node {   // that's C++:  no need for typedef
    int data;
    struct node *child1,*child2;
    Node() : data(0), child1(nullptr), child2(nullptr) {} // Makes sure that every created are first initalized
};
然后再把你的旧马洛克干掉。并构建代码以避免不必要的分配:

if(some condition holds for child1){ // else no link, so n->child1 should be NULL
    new1=new Node; // if you init it here, no need to free in an else !!
    build(new1,...);
    n->child1 = new1;
    ...
}
if (... child2) { ... }
但是,请注意,分配了
new
的poitner应使用
delete
发布,并使用
free()
注意

编辑:您的代码段中存在不匹配:

traverse(&root);  // you send here a Node* 

void traverse(Node n){  // but your function defines an argument by value !
   ...
}

检查编译器中的一些警告是否过多,代码中是否没有滥用强制转换

这应该标记为C,而不是C++是的
malloc()
是C而不是C++谢谢你们,我会更改标记的。但是我的代码是.cpp文件,如果我像这样使用malloc还可以吗?你能发布traverse()代码吗。您可以使用
new1=newnode而不是谢谢,我确实为每个新节点设置了默认值。你说得对,我总是分配两个子节点,但不能确保它应该保留在树中。但我想那没关系。。。至于malloc,我确实打印了其中的数据,所以我认为它是有效的。@cshushu这很好,但是你不能无条件地将你的孩子链接到他们的父母。在代码中,移动n->child1=new1;n->child2=new2;在if(条件)之外。并非所有节点都有2个子节点,很抱歉,我没有显示我的实际意思,我已经编辑了代码并添加了注释。当子节点的条件不成立时,应该如何处理?你是C++,因为它们会丢失/泄漏吗?我刚刚离开它,没有链接到任何节点,我修改了它们,以便它们被释放,但是没有改变任何东西:(谢谢,我刚才试了C++一分钟,但是结果是一样的。我已经编辑了我的答案。你能按照建议检查你的编译器消息吗?
traverse(&root);  // you send here a Node* 

void traverse(Node n){  // but your function defines an argument by value !
   ...
}