Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/72.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_Recursion_Stack Overflow - Fatal编程技术网

C语言中使用递归的堆栈溢出

C语言中使用递归的堆栈溢出,c,recursion,stack-overflow,C,Recursion,Stack Overflow,我一直在疯狂地寻找答案,但毫无结果;我创建了一个四叉树,它应该对结构声明的1000多个对象的数组进行排序: typedef struct node { char is_leaf; struct Particle *p; double m; double center_x; double center_y; double width; struct node *sw; struct node *nw; str

我一直在疯狂地寻找答案,但毫无结果;我创建了一个四叉树,它应该对结构声明的1000多个对象的数组进行排序:

typedef struct node
{
    char     is_leaf;
    struct Particle *p;
    double    m;

    double center_x;
    double center_y;
    double width;

    struct node *sw;
    struct node *nw;
    struct node *se;
    struct node *ne;

} node;
使用以下函数将其转换为四叉树:

node* quadtree_insert(node *n, struct Particle *p, double center_x, double center_y, double width)
{
    if(n == NULL)
    {
        n = (node*)malloc(sizeof(node));
        n->is_leaf = 1;

        n->p = p;
        //n->m = 0.1;

        n->sw = NULL;
        n->se = NULL;
        n->nw = NULL;
        n->ne = NULL;
        if(width < 1e-300){
            n->width = 1e-300;
            }
        else
            n->width    = width;
        return n;
    }
    else{
        //n = (node*)malloc(sizeof(node));
        double x;
        double y;
        if(width < 1e-300){
            width = 1e-300;
            }
        if(n->is_leaf == 1) //! that is, if the node is not a branch
        {
                        x = (double)n->p->x_pos;
            y = (double)n->p->y_pos;

            if(x <= center_x && y <= center_y) //! first quadrant
            {
                n->sw = quadtree_insert(n->sw, n->p, center_x * 0.5, center_y * 0.5, width * 0.5);
            }
            else if(x <= center_x && y > center_y) //! second quadrant
            {
                n->nw = quadtree_insert(n->nw, n->p, center_x * 0.5, center_y + center_y * 0.5, width * 0.5);
            }
            else if(x > center_x && y <= center_y) //! third quadrant
            {
                n->se = quadtree_insert(n->se, n->p, center_x + center_x * 0.5, center_y * 0.5, width * 0.5);
            }
            else //! fourth quadrant
            {
                n->ne = quadtree_insert(n->ne, n->p, center_x + center_x * 0.5, center_y + center_y * 0.5, width * 0.5);
            }

            n->p = NULL; //! sets branch pointer to nothing...
            n->is_leaf = 0;
                    }
        //}

        x = (double)p->x_pos;
        y = (double)p->y_pos;

        if(x <= center_x && y <= center_y) //! first quadrant
        {
            n->sw = quadtree_insert(n->sw, p, center_x * 0.5, center_y * 0.5, width * 0.5);

        }
        else if(x <= center_x && y > center_y) //! second quadrant
        {
            n->nw = quadtree_insert(n->nw, p, center_x * 0.5, center_y + center_y * 0.5, width * 0.5);

        }
        else if(x > center_x && y <= center_y) //! third quadrant
        {
            n->se = quadtree_insert(n->se, p, center_x + center_x * 0.5, center_y * 0.5, width * 0.5);

        }
        else //! fourth quadrant
        {
            n->ne = quadtree_insert(n->ne, p, center_x + center_x * 0.5, center_y + center_y * 0.5, width * 0.5);            
        }
        return n;
    }
}
每次迭代后,在for循环之后,根是自由的,代码适用于小于~200的样本,valgrind没有给出这些样本的错误。除此之外还有一个中间函数,它对粒子执行一些算术运算:

double quadtree_calculate_forcey(struct Particle *p, node *n, double theta_max, double delta_t, int numP, double epsilon, double G)
{
    if(n != NULL)
    {
            double d_x      = (n->center_x - p->x_pos);
                double d_y      = (n->center_y - p->y_pos);
        double r_2     = d_x * d_x + d_y * d_y;
        r_2 = sqrt(r_2) + epsilon;
        if(theta_max <= (n->width / r_2) && !n->is_leaf){
                double a = 0;
            if(n->sw != NULL)
                        a += quadtree_calculate_forcey(p, n->sw, theta_max, delta_t, numP, epsilon, G);
                    if(n->nw != NULL)
                        a += quadtree_calculate_forcey(p, n->nw, theta_max, delta_t, numP, epsilon, G);
                    if(n->se != NULL)
                        a += quadtree_calculate_forcey(p, n->se, theta_max, delta_t, numP, epsilon, G);
                    if(n->ne != NULL)
                        a += quadtree_calculate_forcey(p, n->ne, theta_max, delta_t, numP, epsilon, G);
                    return a;
        }
        else    
                {
                double fy;
            double mass;
           if(d_x == 0 && d_y == 0){ // could be comparing the same star
                 //printf("RÖÖÖVHATT\n");  
                  return 0;
            }
            else{
            //printf("MASS : %f\n", n->m);
                  mass = n->m;
                  //printf("MASS : %f\n", mass);
                  fy = G * (mass * p->mass/ pow(r_2,3)) * d_y;   
                            //printf("DY:%f   DX:%f   R_2:%f   MASSA:%f\n",d_y, d_x, r_2 - epsilon, mass);          
                     // printf("HIT SKA JAG: %f\n",d_y);
                  return fy;              
                 }
        }
    }
    return 0.0;
}
部分分析 我可以肯定问题主要是由于
quadtree\u insert()
的主
else
子句中的大量重复代码(接近重复代码)造成的。我已经用注释标记了片段1A和1B的开头,现在片段1B也用ifdef DO_REPEAT和endif构成框架

    else
    {
        /* Fragment 1A */
        // n = (node*)malloc(sizeof(node));
        double x;
        double y;
        if (width < 1e-300)
        {
            width = 1e-300;
        }
        if (n->is_leaf == 1) // ! that is, if the node is not a branch
        {
            x = (double)n->p->x_pos;
            y = (double)n->p->y_pos;

            if (x <= center_x && y <= center_y) // ! first quadrant
            {
                n->sw = quadtree_insert(n->sw, n->p, center_x * 0.5, center_y * 0.5, width * 0.5);
            }
            else if (x <= center_x && y > center_y) // ! second quadrant
            {
                n->nw = quadtree_insert(n->nw, n->p, center_x * 0.5, center_y + center_y * 0.5, width * 0.5);
            }
            else if (x > center_x && y <= center_y) // ! third quadrant
            {
                n->se = quadtree_insert(n->se, n->p, center_x + center_x * 0.5, center_y * 0.5, width * 0.5);
            }
            else // ! fourth quadrant
            {
                n->ne = quadtree_insert(n->ne, n->p, center_x + center_x * 0.5, center_y + center_y * 0.5, width * 0.5);
            }

            n->p = NULL; // ! sets branch pointer to nothing...
            n->is_leaf = 0;
        }

#ifdef DO_REPEAT
        /* Fragment 1B */
        x = (double)p->x_pos;
        y = (double)p->y_pos;

        if (x <= center_x && y <= center_y) // ! first quadrant
        {
            n->sw = quadtree_insert(n->sw, p, center_x * 0.5, center_y * 0.5, width * 0.5);
        }
        else if (x <= center_x && y > center_y) // ! second quadrant
        {
            n->nw = quadtree_insert(n->nw, p, center_x * 0.5, center_y + center_y * 0.5, width * 0.5);
        }
        else if (x > center_x && y <= center_y) // ! third quadrant
        {
            n->se = quadtree_insert(n->se, p, center_x + center_x * 0.5, center_y * 0.5, width * 0.5);
        }
        else // ! fourth quadrant
        {
            n->ne = quadtree_insert(n->ne, p, center_x + center_x * 0.5, center_y + center_y * 0.5, width * 0.5);
        }
#endif /* DO_REPEAT */
        return n;
    }
我使用了一个随机数生成器作为值表:

random -n 10 -T '    { %6:2[1:20]f, %6:2[-100:100]f, %6:2[-100:100]f, %6:2[-100:100]f, %6:2[-100:100]f },'
它在粒子6上为我崩溃了。在大纲中,他说:

即使在我运行它的Mac上,这也表明存在问题;被抑制的东西是可以的,但其余的大部分不是

当编译时没有
-DDO_REPEAT
(正常编译),示例程序将运行到完成。当然,它会泄漏,因为没有代码来释放内存

Particle 0:
Particle 1:
Particle 2:
Particle 3:
Particle 4:
Particle 5:
Particle 6:
Particle 7:
Particle 8:
Particle 9:
==79683== 
==79683== HEAP SUMMARY:
==79683==     in use at exit: 26,580 bytes in 191 blocks
==79683==   total heap usage: 273 allocs, 82 frees, 32,756 bytes allocated
==79683== 
==79683== LEAK SUMMARY:
==79683==    definitely lost: 4,200 bytes in 3 blocks
==79683==    indirectly lost: 2,368 bytes in 7 blocks
==79683==      possibly lost: 4,880 bytes in 45 blocks
==79683==    still reachable: 6,440 bytes in 13 blocks
==79683==         suppressed: 8,692 bytes in 123 blocks
==79683== Rerun with --leak-check=full to see details of leaked memory
请注意,使用的内存比以前少得多

如果由于缺少
DO_REPEAT
而消除的代码实际上是至关重要的,那么错误要么在于该代码,要么在于片段1A中完成的设置工作。然而,在我看来,使用递归调用插入同一粒子两次可能是问题的根源

我还注意到代码中没有使用
quadtree\u calculate\u forcey()
函数;它绝对不是MCVE的一部分


需要片段1B 建议:

请注意,“重复”代码的形式相同,但不详细。也就是说,片段1B使用
n->p
,而片段1A使用
p
。我认为这是有目的的:这个想法似乎是将所有数据(粒子)强制输出到叶节点

并申明:

正如John所说,每个粒子都应该占据一个端点节点。我的怀疑是,这与运动有关,行星排列得如此之好,以至于必须进行荒谬的迭代才能打开两个自由正方形。但我看不到解决我问题的办法,有什么想法吗

逻辑上存在问题,尽管我不完全确定问题是什么。我要做的第一步是在
quadtree\u insert()
中的代码中添加一些指令插入,如下所示:

static node *quadtree_insert(node *n, struct Particle *p, double center_x, double center_y, double width)
{
    printf("Centre (X,Y) = (%6.2f,%6.2f)\n", center_x, center_y);
    if (n == NULL)
    {
        n = (node *)malloc(sizeof(node));
        n->is_leaf = 1;

        n->p = p;
        // n->m = 0.1;

        n->sw = NULL;
        n->se = NULL;
        n->nw = NULL;
        n->ne = NULL;
        if (width < 1e-300)
        {
            n->width = 1e-300;
        }
        else
            n->width    = width;
        return n;
    }
    else
    {
        // n = (node*)malloc(sizeof(node));
        double x;
        double y;
        if (width < 1e-300)
        {
            width = 1e-300;
        }
        if (n->is_leaf == 1) // ! that is, if the node is not a branch
        {
            x = (double)n->p->x_pos;
            y = (double)n->p->y_pos;

            if (x <= center_x && y <= center_y) // ! first quadrant
            {
                printf("Recurse SW 1: ");
                n->sw = quadtree_insert(n->sw, n->p, center_x * 0.5, center_y * 0.5, width * 0.5);
            }
            else if (x <= center_x && y > center_y) // ! second quadrant
            {
                printf("Recurse NW 1: ");
                n->nw = quadtree_insert(n->nw, n->p, center_x * 0.5, center_y + center_y * 0.5, width * 0.5);
            }
            else if (x > center_x && y <= center_y) // ! third quadrant
            {
                printf("Recurse SE 1: ");
                n->se = quadtree_insert(n->se, n->p, center_x + center_x * 0.5, center_y * 0.5, width * 0.5);
            }
            else // ! fourth quadrant
            {
                printf("Recurse NE 1: ");
                n->ne = quadtree_insert(n->ne, n->p, center_x + center_x * 0.5, center_y + center_y * 0.5, width * 0.5);
            }

            n->p = NULL; // ! sets branch pointer to nothing...
            n->is_leaf = 0;
        }

        x = (double)p->x_pos;
        y = (double)p->y_pos;

        if (x <= center_x && y <= center_y) // ! first quadrant
        {
            printf("Recurse SW 2: ");
            n->sw = quadtree_insert(n->sw, p, center_x * 0.5, center_y * 0.5, width * 0.5);
        }
        else if (x <= center_x && y > center_y) // ! second quadrant
        {
            printf("Recurse NW 2: ");
            n->nw = quadtree_insert(n->nw, p, center_x * 0.5, center_y + center_y * 0.5, width * 0.5);
        }
        else if (x > center_x && y <= center_y) // ! third quadrant
        {
            printf("Recurse SE 2: ");
            n->se = quadtree_insert(n->se, p, center_x + center_x * 0.5, center_y * 0.5, width * 0.5);
        }
        else // ! fourth quadrant
        {
            printf("Recurse NE 2: ");
            n->ne = quadtree_insert(n->ne, p, center_x + center_x * 0.5, center_y + center_y * 0.5, width * 0.5);
        }
        return n;
    }
}
我对这里的一些处理和粒子4的条目数量感到有点惊讶。这可能说明了问题所在

然后它处理粒子6:

Particle 6: Centre (X,Y) = (  0.50,  0.50)
Recurse SW 2: Centre (X,Y) = (  0.25,  0.25)
Recurse SW 1: Centre (X,Y) = (  0.12,  0.12)
Recurse SW 2: Centre (X,Y) = (  0.12,  0.12)
Recurse SW 1: Centre (X,Y) = (  0.06,  0.06)
Recurse SW 2: Centre (X,Y) = (  0.06,  0.06)
Recurse SW 1: Centre (X,Y) = (  0.03,  0.03)
Recurse SW 2: Centre (X,Y) = (  0.03,  0.03)
Recurse SW 1: Centre (X,Y) = (  0.02,  0.02)
Recurse SW 2: Centre (X,Y) = (  0.02,  0.02)
Recurse SW 1: Centre (X,Y) = (  0.01,  0.01)
Recurse SW 2: Centre (X,Y) = (  0.01,  0.01)
Recurse SW 1: Centre (X,Y) = (  0.00,  0.00)
Recurse SW 2: Centre (X,Y) = (  0.00,  0.00)
Recurse SW 1: Centre (X,Y) = (  0.00,  0.00)
Recurse SW 2: Centre (X,Y) = (  0.00,  0.00)
Recurse SW 1: Centre (X,Y) = (  0.00,  0.00)
Recurse SW 2: Centre (X,Y) = (  0.00,  0.00)
从那以后就变得很乏味了。你需要问的问题是“这一点会发生什么”?有一个函数来转储四叉树结构可能也是个好主意

这基本上表明您尚未充分分析添加点的条件。我不清楚当插入位于东南或东北象限时,为什么要将中心坐标乘以1.5,当插入位于西南或西北象限时,为什么要将中心坐标乘以0.5(也不清楚为什么要使用加法乘法而不是简单的乘法)

宽度
小于
1e-300
的测试有点令人担忧。假设您使用值
1.0
调用函数,那么每次递归时将宽度减半需要一段时间才能变小

更好的追踪可以报告
x
y
的值以及中心坐标。

部分分析 我可以肯定问题主要是由于
quadtree\u insert()
的主
else
子句中的大量重复代码(接近重复代码)造成的。我已经用注释标记了片段1A和1B的开头,现在片段1B也用ifdef DO_REPEAT和endif构成框架

    else
    {
        /* Fragment 1A */
        // n = (node*)malloc(sizeof(node));
        double x;
        double y;
        if (width < 1e-300)
        {
            width = 1e-300;
        }
        if (n->is_leaf == 1) // ! that is, if the node is not a branch
        {
            x = (double)n->p->x_pos;
            y = (double)n->p->y_pos;

            if (x <= center_x && y <= center_y) // ! first quadrant
            {
                n->sw = quadtree_insert(n->sw, n->p, center_x * 0.5, center_y * 0.5, width * 0.5);
            }
            else if (x <= center_x && y > center_y) // ! second quadrant
            {
                n->nw = quadtree_insert(n->nw, n->p, center_x * 0.5, center_y + center_y * 0.5, width * 0.5);
            }
            else if (x > center_x && y <= center_y) // ! third quadrant
            {
                n->se = quadtree_insert(n->se, n->p, center_x + center_x * 0.5, center_y * 0.5, width * 0.5);
            }
            else // ! fourth quadrant
            {
                n->ne = quadtree_insert(n->ne, n->p, center_x + center_x * 0.5, center_y + center_y * 0.5, width * 0.5);
            }

            n->p = NULL; // ! sets branch pointer to nothing...
            n->is_leaf = 0;
        }

#ifdef DO_REPEAT
        /* Fragment 1B */
        x = (double)p->x_pos;
        y = (double)p->y_pos;

        if (x <= center_x && y <= center_y) // ! first quadrant
        {
            n->sw = quadtree_insert(n->sw, p, center_x * 0.5, center_y * 0.5, width * 0.5);
        }
        else if (x <= center_x && y > center_y) // ! second quadrant
        {
            n->nw = quadtree_insert(n->nw, p, center_x * 0.5, center_y + center_y * 0.5, width * 0.5);
        }
        else if (x > center_x && y <= center_y) // ! third quadrant
        {
            n->se = quadtree_insert(n->se, p, center_x + center_x * 0.5, center_y * 0.5, width * 0.5);
        }
        else // ! fourth quadrant
        {
            n->ne = quadtree_insert(n->ne, p, center_x + center_x * 0.5, center_y + center_y * 0.5, width * 0.5);
        }
#endif /* DO_REPEAT */
        return n;
    }
我使用了一个随机数生成器作为值表:

random -n 10 -T '    { %6:2[1:20]f, %6:2[-100:100]f, %6:2[-100:100]f, %6:2[-100:100]f, %6:2[-100:100]f },'
它在粒子6上为我崩溃了。在大纲中,他说:

即使在我运行它的Mac上,这也表明存在问题;被抑制的东西是可以的,但其余的大部分不是

当编译时没有
-DDO_REPEAT
(正常编译),示例程序将运行到完成。当然,它会泄漏,因为没有代码来释放内存

Particle 0:
Particle 1:
Particle 2:
Particle 3:
Particle 4:
Particle 5:
Particle 6:
Particle 7:
Particle 8:
Particle 9:
==79683== 
==79683== HEAP SUMMARY:
==79683==     in use at exit: 26,580 bytes in 191 blocks
==79683==   total heap usage: 273 allocs, 82 frees, 32,756 bytes allocated
==79683== 
==79683== LEAK SUMMARY:
==79683==    definitely lost: 4,200 bytes in 3 blocks
==79683==    indirectly lost: 2,368 bytes in 7 blocks
==79683==      possibly lost: 4,880 bytes in 45 blocks
==79683==    still reachable: 6,440 bytes in 13 blocks
==79683==         suppressed: 8,692 bytes in 123 blocks
==79683== Rerun with --leak-check=full to see details of leaked memory
请注意,使用的内存比以前少得多

如果由于缺少
DO_REPEAT
而消除的代码实际上是至关重要的,那么错误要么在于该代码,要么在于片段1A中完成的设置工作。然而,在我看来,使用递归调用插入同一粒子两次可能是问题的根源

我还注意到代码中没有使用
quadtree\u calculate\u forcey()
函数;它绝对不是MCVE的一部分


需要片段1B 建议:

请注意,“重复”代码的形式相同,但不详细。也就是说,片段1B使用
n->p
,而片段1A使用
p
。我认为这是有目的的:这个想法似乎是将所有数据(粒子)强制输出到叶节点

并申明:

正如John所说,每个粒子都应该占据一个端点节点。我的怀疑是,这与运动有关,行星排列得如此之好,以至于必须进行荒谬的迭代才能打开两个自由正方形。但我看不到解决我问题的办法,有什么想法吗

逻辑上存在问题,尽管我不完全确定问题是什么。我要做的第一步是在
quadtree\u insert()
中的代码中添加一些指令插入,如下所示:

static node *quadtree_insert(node *n, struct Particle *p, double center_x, double center_y, double width)
{
    printf("Centre (X,Y) = (%6.2f,%6.2f)\n", center_x, center_y);
    if (n == NULL)
    {
        n = (node *)malloc(sizeof(node));
        n->is_leaf = 1;

        n->p = p;
        // n->m = 0.1;

        n->sw = NULL;
        n->se = NULL;
        n->nw = NULL;
        n->ne = NULL;
        if (width < 1e-300)
        {
            n->width = 1e-300;
        }
        else
            n->width    = width;
        return n;
    }
    else
    {
        // n = (node*)malloc(sizeof(node));
        double x;
        double y;
        if (width < 1e-300)
        {
            width = 1e-300;
        }
        if (n->is_leaf == 1) // ! that is, if the node is not a branch
        {
            x = (double)n->p->x_pos;
            y = (double)n->p->y_pos;

            if (x <= center_x && y <= center_y) // ! first quadrant
            {
                printf("Recurse SW 1: ");
                n->sw = quadtree_insert(n->sw, n->p, center_x * 0.5, center_y * 0.5, width * 0.5);
            }
            else if (x <= center_x && y > center_y) // ! second quadrant
            {
                printf("Recurse NW 1: ");
                n->nw = quadtree_insert(n->nw, n->p, center_x * 0.5, center_y + center_y * 0.5, width * 0.5);
            }
            else if (x > center_x && y <= center_y) // ! third quadrant
            {
                printf("Recurse SE 1: ");
                n->se = quadtree_insert(n->se, n->p, center_x + center_x * 0.5, center_y * 0.5, width * 0.5);
            }
            else // ! fourth quadrant
            {
                printf("Recurse NE 1: ");
                n->ne = quadtree_insert(n->ne, n->p, center_x + center_x * 0.5, center_y + center_y * 0.5, width * 0.5);
            }

            n->p = NULL; // ! sets branch pointer to nothing...
            n->is_leaf = 0;
        }

        x = (double)p->x_pos;
        y = (double)p->y_pos;

        if (x <= center_x && y <= center_y) // ! first quadrant
        {
            printf("Recurse SW 2: ");
            n->sw = quadtree_insert(n->sw, p, center_x * 0.5, center_y * 0.5, width * 0.5);
        }
        else if (x <= center_x && y > center_y) // ! second quadrant
        {
            printf("Recurse NW 2: ");
            n->nw = quadtree_insert(n->nw, p, center_x * 0.5, center_y + center_y * 0.5, width * 0.5);
        }
        else if (x > center_x && y <= center_y) // ! third quadrant
        {
            printf("Recurse SE 2: ");
            n->se = quadtree_insert(n->se, p, center_x + center_x * 0.5, center_y * 0.5, width * 0.5);
        }
        else // ! fourth quadrant
        {
            printf("Recurse NE 2: ");
            n->ne = quadtree_insert(n->ne, p, center_x + center_x * 0.5, center_y + center_y * 0.5, width * 0.5);
        }
        return n;
    }
}
我对一些程序感到有点惊讶
Particle 0: Centre (X,Y) = (  0.50,  0.50)
Particle 1: Centre (X,Y) = (  0.50,  0.50)
Recurse NE 1: Centre (X,Y) = (  0.75,  0.75)
Recurse SE 2: Centre (X,Y) = (  0.75,  0.25)
Particle 2: Centre (X,Y) = (  0.50,  0.50)
Recurse SE 2: Centre (X,Y) = (  0.75,  0.25)
Recurse SE 1: Centre (X,Y) = (  1.12,  0.12)
Recurse SE 2: Centre (X,Y) = (  1.12,  0.12)
Recurse SE 1: Centre (X,Y) = (  1.69,  0.06)
Recurse SE 2: Centre (X,Y) = (  1.69,  0.06)
Recurse SW 1: Centre (X,Y) = (  0.84,  0.03)
Recurse SE 2: Centre (X,Y) = (  2.53,  0.03)
Particle 3: Centre (X,Y) = (  0.50,  0.50)
Recurse SW 2: Centre (X,Y) = (  0.25,  0.25)
Particle 4: Centre (X,Y) = (  0.50,  0.50)
Recurse NE 2: Centre (X,Y) = (  0.75,  0.75)
Recurse NE 1: Centre (X,Y) = (  1.12,  1.12)
Recurse NE 2: Centre (X,Y) = (  1.12,  1.12)
Recurse NE 1: Centre (X,Y) = (  1.69,  1.69)
Recurse NE 2: Centre (X,Y) = (  1.69,  1.69)
Recurse NE 1: Centre (X,Y) = (  2.53,  2.53)
Recurse NE 2: Centre (X,Y) = (  2.53,  2.53)
Recurse NE 1: Centre (X,Y) = (  3.80,  3.80)
Recurse NE 2: Centre (X,Y) = (  3.80,  3.80)
Recurse NE 1: Centre (X,Y) = (  5.70,  5.70)
Recurse NE 2: Centre (X,Y) = (  5.70,  5.70)
Recurse NE 1: Centre (X,Y) = (  8.54,  8.54)
Recurse NE 2: Centre (X,Y) = (  8.54,  8.54)
Recurse NE 1: Centre (X,Y) = ( 12.81, 12.81)
Recurse NE 2: Centre (X,Y) = ( 12.81, 12.81)
Recurse NE 1: Centre (X,Y) = ( 19.22, 19.22)
Recurse NE 2: Centre (X,Y) = ( 19.22, 19.22)
Recurse NE 1: Centre (X,Y) = ( 28.83, 28.83)
Recurse NE 2: Centre (X,Y) = ( 28.83, 28.83)
Recurse NE 1: Centre (X,Y) = ( 43.25, 43.25)
Recurse NE 2: Centre (X,Y) = ( 43.25, 43.25)
Recurse NE 1: Centre (X,Y) = ( 64.87, 64.87)
Recurse NE 2: Centre (X,Y) = ( 64.87, 64.87)
Recurse SE 1: Centre (X,Y) = ( 97.31, 32.44)
Recurse NE 2: Centre (X,Y) = ( 97.31, 97.31)
Particle 5: Centre (X,Y) = (  0.50,  0.50)
Recurse NW 2: Centre (X,Y) = (  0.25,  0.75)
Particle 6: Centre (X,Y) = (  0.50,  0.50)
Recurse SW 2: Centre (X,Y) = (  0.25,  0.25)
Recurse SW 1: Centre (X,Y) = (  0.12,  0.12)
Recurse SW 2: Centre (X,Y) = (  0.12,  0.12)
Recurse SW 1: Centre (X,Y) = (  0.06,  0.06)
Recurse SW 2: Centre (X,Y) = (  0.06,  0.06)
Recurse SW 1: Centre (X,Y) = (  0.03,  0.03)
Recurse SW 2: Centre (X,Y) = (  0.03,  0.03)
Recurse SW 1: Centre (X,Y) = (  0.02,  0.02)
Recurse SW 2: Centre (X,Y) = (  0.02,  0.02)
Recurse SW 1: Centre (X,Y) = (  0.01,  0.01)
Recurse SW 2: Centre (X,Y) = (  0.01,  0.01)
Recurse SW 1: Centre (X,Y) = (  0.00,  0.00)
Recurse SW 2: Centre (X,Y) = (  0.00,  0.00)
Recurse SW 1: Centre (X,Y) = (  0.00,  0.00)
Recurse SW 2: Centre (X,Y) = (  0.00,  0.00)
Recurse SW 1: Centre (X,Y) = (  0.00,  0.00)
Recurse SW 2: Centre (X,Y) = (  0.00,  0.00)
else if (x <= center_x && y > center_y) // ! second quadrant
{
    n->nw = quadtree_insert(n->nw, n->p, center_x * 0.5, center_y + center_y * 0.5, width * 0.5);
}
// adjust as needed:
#define MIN_PARTICLE_SEPARATION 1e-300

void quadtree_insert_helper(node *n, Particle *p, double center_x,
        double center_y, double width) {
    width *= 0.5;

    double new_center_x = center_x
            + width * ((p->x_pos <= center_x) ? -0.5 : 0.5);
    double new_center_y = center_y
            + width * ((p->y_pos <= center_y) ? -0.5 : 0.5);
    node **quad;

    if (new_center_x <= center_x && new_center_y <= center_y) {
        //! first quadrant
        quad = &n->sw;
    } else if (new_center_x <= center_x && new_center_y > center_y) {
        //! second quadrant
        quad = &n->nw;
    } else if (new_center_x > center_x && new_center_y <= center_y) {
        //! third quadrant
        quad = &n->se;
    } else {
        //! fourth quadrant
        quad = &n->ne;
    }
    *quad = quadtree_insert(*quad, p, new_center_x, new_center_y, width);
}

node* quadtree_insert(node *n, struct Particle *p, double center_x,
        double center_y, double width) {
    if (n == NULL) {
        n = malloc(sizeof(*n));
        n->is_leaf = 1;
        n->p = p;
        //n->m = 0.1;
        n->sw = NULL;
        n->se = NULL;
        n->nw = NULL;
        n->ne = NULL;
        n->center_x = center_x;
        n->center_y = center_y;
        n->width = width;
    } else if (n->is_leaf && (with <= MIN_PARTICLE_SEPARATION)) {
        // ... merge particles ...
    } else {
        if (n->is_leaf) { //! that is, if the node is not a branch
            quadtree_insert_helper(n, n->p, center_x, center_y, width);
            //! the node is now a branch
            n->p = NULL;
            n->is_leaf = 0;
        }

        quadtree_insert_helper(n, p, center_x, center_y, width);
    }

    return n;
}