我现在正在实施Barnes-Hut Algorithms来模拟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);
.
}
这是函数set_root_and_build(); 我已将子指针设置为NULL,但最初没有显示它。
void set_root_and_build(){
root.data = ...;
..// set child1 and child2 =NULL;
build(&root,...); // ... part are values of data for it's child
}
并建立:
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()函数递归时打印出正确的数据。
但是当它返回main函数并调用traverse()时,由于分段错误而失败。
我试图在traverse()中打印所有东西,发现只有root,root.child1,root.child2就像我刚才提到的那样存储了这个值。
由于我必须多次调用build(),甚至并行调用new1和new2,因此不能将new1和new2定义为全局变量......(但我不认为它们会导致问题)
有谁知道哪里出错了?
=====================
带有调试信息的遍历部分:
void traverse(Node n){
...//print out data of n
if(n.child1!=NULL)
traverse(*(n.child1))
...//same for child2
}
答案 0 :(得分:2)
当条件不成立时,您可能无法正确设置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
}
答案 1 :(得分:2)
树遍历中的问题是你肯定会处理树,直到找到一个NULL的节点指针。
不幸的是,当您创建节点时,这些节点既不会使用malloc()
也不会使用new
初始化(它会使用calloc()
进行初始化,但cpp代码中的这种做法与{ {1}})。所以你的遍历继续循环/递归随机指针的永恒之地。
我建议你利用cpp并稍微改变你的结构:
malloc()
然后摆脱你的旧mallocs。并构造代码以避免不必要的分配:
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
一同发布,并注明delete
。
修改:您的代码段不匹配:
free()
检查您是否没有从编译器中获取一些警告,并且您的代码中没有滥用强制转换。