【问题标题】:StackOverflow on Recursive Function递归函数中的堆栈溢出
【发布时间】:2015-01-07 03:48:57
【问题描述】:

我有以下函数,它应该产生笛卡尔平面中的所有坐标,我可以在 n 步内从原点到达:

原点是“位置”,步数是“强度”,即 int 1-10。但是,我不断收到 stackoverflow 错误。每次我调用它时,我都会在 ArrayList 位置上调用 clear 。想法?

更新代码:

// Returns all positions reachable in 'strength' steps
    public ArrayList<Int2D> findEscapeSpace(Int2D location, Field f) {
        // Are we still within the given radius?
        if((Math.abs(location.getX() - this.location.getX()) + Math.abs(location.getY() - this.location.getY())) < strength) {
            System.out.println("Starting on " + location);
            // If this position is not contained already, and if it doesn't contain a wall
            if(!positions.contains(location) && f.wallField.getObjectsAtLocation(location) == null) {
                positions.add(location);
                System.out.println("added " + location);
            }

            // Getting neighboring positions
            ArrayList<Int2D> neigh = findNeighPos(location, f);

            for(Int2D pos : neigh) {
                System.out.println("looking into " + pos + " at depth " + (Math.abs(location.getX() - this.location.getX()) + Math.abs(location.getY() - this.location.getY())) + " and strength " + strength);

                if(!positions.contains(pos))
                    findEscapeSpace(pos, f);

            }

        }
        System.out.println(positions.size());
        return positions;

    }

旧代码

public ArrayList<Int2D> positions = new ArrayList<Int2D>();

    // Returns all positions reachable in 'strength' steps
    public ArrayList<Int2D> findEscapeSpace(Int2D location, Field f) {

        // Are we still within the given radius?
        if((Math.abs(location.getX() - this.location.getX()) + Math.abs(location.getY() - this.location.getY())) < strength) {
            // If this position is not contained already, and if it doesn't contain a wall
            if(!positions.contains(location) && f.wallField.getObjectsAtLocation(location) == null)
                positions.add(location);

            // Getting neighboring positions
            ArrayList<Int2D> neigh = findNeighPos(location, f);

            for(Int2D pos : neigh) {

                findEscapeSpace(pos, f);

            }

        }

        return positions;

    }

public ArrayList<Int2D> findNeighPos(Int2D currentP, Field f) {

        ArrayList neighPositions = new ArrayList<Int2D>();

        int cx = currentP.getX();
        int cy = currentP.getY();

        int maxY = f.HEIGHT-1;
        int maxX = f.WIDTH-1;

        // A few checks to make sure we're not going off tack (literally)

        if(cx > 0 && cy < maxY)
            neighPositions.add(new Int2D(cx-1, cy+1));

        if(cy < maxY)
            neighPositions.add(new Int2D(cx, cy+1));

        if(cx < maxX && cy < maxY)
            neighPositions.add(new Int2D(cx+1, cy+1));

        if(cx > 0)
            neighPositions.add(new Int2D(cx-1, cy));

        if(cx < maxX)
            neighPositions.add(new Int2D(cx+1, cy));

        if(cx > 0 && cy > 0)
            neighPositions.add(new Int2D(cx-1, cy-1));

        if(cy > 0)
            neighPositions.add(new Int2D(cx, cy-1));

        if(cx < maxX && cy > 0)
            neighPositions.add(new Int2D(cx+1, cy-1));

        return neighPositions;

    }

【问题讨论】:

    标签: java recursion stack-overflow


    【解决方案1】:

    您的递归似乎没有终止条件。看起来您可能希望将 strength 作为参数传递给 findEscapeSpace(),并且当该方法递归时,它传递的值比传递给它的值小一。

    除此之外,您的算法看起来相当低效,因为它可能会多次生成和测试许多可到达的单元格,而且,检查每个单元格是否已经找到的成本相对较高。但这是下一个要克服的问题。

    【讨论】:

    • (Math.abs(location.getX() - this.location.getX()) + Math.abs(location.getY() - this.location.getY()))
    • 这只是确保您不会继续从无法访问的单元格中递归。正如我已经观察到的那样,您的代码无法避免多次生成和测试相同的单元格。例如,如果您从 (5,5) 开始,那么它将递归到 (6,6) 等,然后从那里递归回 (5,5) 等。这将无限期地持续下去。
    • 澄清一下:您的程序将执行无限重复类似于我在之前的评论中描述的那个,但它不会以我提供的精确轨迹为例。它实际上会尽可能地移动到左上角,并在那里进入一个重复的循环。
    • 好吧,您的距离计算似乎假设移动只能是水平或垂直的。生成的可访问空间将是菱形的,x 和 y 坐标轴平行于其对角线(不包括任何边界或障碍物的影响)。如果移动也可以是对角线的,这样可访问空间应该是正方形,坐标轴平行于其边缘,那么您应该将距离计算为 x 和 y 差异的最大值,而不是它们的总和.
    • 您修改后的代码已经更好了。此时最大的效率问题可能围绕positions.contains()。如果positionsList,那么contains() 的每次调用都需要线性搜索,总体上是O(strength^3)。如果您的 Int2D 类具有合适的 equals()hashCode() 方法,那么您可以通过将 positions 更改为 HashSet 来将其改进为 O(strength^2)。或者,您可以保留一个记分板数组,用于跟踪访问过的位置,以便您可以仅基于坐标进行测试。
    猜你喜欢
    • 2017-10-20
    • 1970-01-01
    • 2011-02-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多