使用递归进行 3D 数组操作——导致 ***(不是无限的!)

Posted

技术标签:

【中文标题】使用递归进行 3D 数组操作——导致 ***(不是无限的!)【英文标题】:Using Recursion for 3D Array Manipulation -- Causing *** (not Infinite!) 【发布时间】:2013-04-24 01:49:33 【问题描述】:

我昨天最近发布了一个关于类似问题的问题,但我编写了一些不同的代码,现在遇到了不同的问题。这是导致 *** 的代码。

** 请注意,3D 网格数组包含超过 100 万个元素,并且可以达到大约 6400 万个元素(存储枚举)。

** 另请注意,这不是无穷大。在小型数据集上,该算法运行良好。

这可能是由极端递归引起的吗?我该如何处理(这是我算法的重要组成部分!)?我已经进行了一些研究,并且听说过使用队列,即使只是大量的 for 循环。

什么会降低导致堆栈溢出的可能性?

谢谢!

/**
 * Fills all void cells in the 3D grid of Atom.
 *
 * @param x
 *            The starting x coordinate
 * @param y
 *            The starting y coordinate
 * @param z
 *            The starting z coordinate
 */
private void fillAllVoidCells(int x, int y, int z)

    // Base case -- If not BLOATED_ATOM, BOUNDING_BOX,
    // or VOID then must be a cavity (only 4 CellType
    // enum types.
    if ((grid[x][y][z] == CellType.BLOATED_ATOM)
        || grid[x][y][z] == CellType.BOUNDING_BOX
        || grid[x][y][z] == CellType.VOID)
    
        // Pop off runtime stack
        return;
    
    else
    
        // Set to void then check all surrounding cells.
        grid[x][y][z] = CellType.VOID;

        fillAllVoidCells(x + 1, y, z); // right
        fillAllVoidCells(x - 1, y, z); // left
        fillAllVoidCells(x, y + 1, z); // in front
        fillAllVoidCells(x, y - 1, z); // behind
        fillAllVoidCells(x, y, z + 1); // above
        fillAllVoidCells(x, y, z - 1); // below
    

===== 编辑 ====== 使用堆栈实现的新方法(根据 Roee Gavirel 的帮助) 这会是一个正确的实现吗?

   // ----------------------------------------------------------
    /**
     * Fills all void cells in the 3D grid of Atom.
     *
     * @param x
     *            The starting x coordinate
     * @param y
     *            The starting y coordinate
     * @param z
     *            The starting z coordinate
     */
    private void fillAllVoidCells(int x, int y, int z)
    
        Point p = new Point(x, y, z);

        stack.push(p);

        while (!stack.isEmpty())
            p = stack.top();
        stack.pop();

        // Base case -- If not BLOATED_ATOM, BOUNDING_BOX,
        // or VOID then must be a cavity (only 4 CellType
        // enum types.
        CellType state = grid[p.x][p.y][p.z];

        if ((state == CellType.BLOATED_ATOM) || state == CellType.BOUNDING_BOX
            || state == CellType.VOID)
        
            return;
        
        else
        
            // Set to void then check all surrounding cells.
            grid[p.x][p.y][p.z] = CellType.VOID;
            Point tempP = p;

            tempP.x = p.x - 1;
            stack.push(tempP);
            tempP.x = p.x + 1;
            stack.push(tempP);
            tempP.x = p.x; // return to original x coordinate

            tempP.y = p.y - 1;
            stack.push(tempP);
            tempP.y = p.y + 1;
            stack.push(tempP);
            tempP.y = p.y; // return to original y coordiante

            tempP.z = p.z - 1;
            stack.push(tempP);
            tempP.z = p.z + 1;
            stack.push(tempP);
            tempP.z = p.z; // return to original z coordinate
        
    

【问题讨论】:

【参考方案1】:

这很可能导致溢出。您可以(并且应该)做的就是使用您自己的数据堆栈并避免递归。

在你的情况下: 1. 有一堆相关点 (x,y,z),其中包含您最初称为 fillAllVoidCells 的点。 2.while堆栈不为空,你应该检查一下 3.如果是cavity,则将周围的点添加到堆栈中。

==编辑== 类似的东西:

struct point 
    int x,y,z;


private void fillAllVoidCells(int x, int y, int z)

    std::list<point> Ps;
    point p;
    p.x = x;
    p.y = y;
    p.z = z;
    Ps.push_back(p);

    while (!Ps.empty())
        p = Ps.back();
        Ps.pop_back();

        // Base case -- If not BLOATED_ATOM, BOUNDING_BOX,
        // or VOID then must be a cavity (only 4 CellType
        // enum types.
        auto state = grid[p.x][p.y][p.z];
        if ((state == CellType.BLOATED_ATOM)
            || state == CellType.BOUNDING_BOX
            || state == CellType.VOID)
        
            continue;
        
        else
        
            // Set to void then check all surrounding cells.
            grid[p.x][p.y][p.z] = CellType.VOID;

            point tempP = p;
            tempP.x = P.x - 1;    
            Ps.push_back(tempP);
            tempP.x = P.x + 1;    
            Ps.push_back(tempP);
            tempP.y = P.y - 1;    
            Ps.push_back(tempP);
            tempP.y = P.y + 1;    
            Ps.push_back(tempP);
            tempP.z = P.z - 1;    
            Ps.push_back(tempP);
            tempP.z = P.z + 1;    
            Ps.push_back(tempP);
        
    

【讨论】:

嗯,我有点困惑。所以我应该有一个存储数组元素的堆栈,但重要的部分是 3D 数组中的位置对我的程序的其余部分很重要。我正在尝试对 3D 蛋白质进行建模,并且需要适当的 x、y、z 坐标(由 grid[x][y][z] 表示)。我将如何处理? @RichieEpiscopo 我添加了一个代码(未经测试),它将为您提供您应该采取的方向。 非常感谢您!今晚我将尝试在 Java 中实现这一点。这导致 *** 或 OutOfMemory 异常的可能性是什么? (数组有 > 1,000,000 个元素) @RichieEpiscopo 这会导致堆栈溢出,因为您的元素没有保存在堆栈上。关于 OutOfMemory 除非你有 4Mb RAM 我不这么认为(: 再次感谢您的帮助。我在 Java 中添加了一个我相信会起作用的实现。你能检查一下吗?我相信你可能错过的一件事(如果我错了,请纠正我!)是在我将 x 坐标(或 y 或 z)调整为正 1 或负 1 并将它们都推入堆栈后,我设置 tempP 的 x回到原来的x坐标。这是正确的(见上面的注释代码)?

以上是关于使用递归进行 3D 数组操作——导致 ***(不是无限的!)的主要内容,如果未能解决你的问题,请参考以下文章

您如何将其转换为迭代函数而不是使用嵌套循环进行递归?

PHPUnit 是不是有一些内置的递归数组比较函数?

无法检查数组是不是使用递归排序

LSTM 预处理:基于 ID 从 pandas 数据帧构建 3d 数组

php实现快速排序

Javascript递归导致循环结构