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

时间:2015-02-23 18:14:00

标签: c pointers recursion tree structure

我现在正在实施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
}

2 个答案:

答案 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()

检查您是否没有从编译器中获取一些警告,并且您的代码中没有滥用强制转换。