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