使用java中的循环将递归方法转换为非递归方法

时间:2016-10-18 18:29:34

标签: java performance list loops recursion

所以我现在正在制作一个游戏,其中指令是使用存储在标记索引处的整数(在这种情况下为圆形)在数组内向左或向右移动,直到我们可以将圆圈移到最后一个索引数组。数组的最后一个整数始终为0.

例如,

[4] 1 2 3 1 0,这里我们从圆0开始(索引)

我们向右移动4,1 1 2 3 [1] 0

然后1次向右,4 1 2 3 1 [0]。在这里游戏停止,我们赢了。

对于递归方法,我的代码如下:

public static boolean rightWing (int circle, int[] game, List<Integer> checkerList){

int last = game.length-1;

if (circle == last){ // base case for recursion
    return true;
}

if (circle < 0){ // if we go out of bounds on the left
    return false;
}

if (circle > last){ // if we go out of bounds on the right
    return false;
}

if (checkerList.contains(circle)){ // check for the impossible case 
    return false;
}

checkerList.add(circle); // adds the circle value for the last check to checkerList so we can check for the impossible case

int moveRight = circle + game[circle]; // these two integers help the game move according to the value of the int at circle
int moveLeft = circle - game[circle];

return rightWing( moveRight, game, checkerList) || rightWing(moveLeft, game,checkerList);
}

这很好用,但唯一的问题是它的递归和缓慢。我试图使用循环和堆栈/队列重新设计它以使其更有效率,但是在写完这个之后我陷入困境(伪):

   Boolean rightWing (int circle, List<int> game, List<int> checkerList)

Int lastPlace = game.size() - 1

For int i <- 0 to game.size() - 1 do

    If i equals lastPlace then // returns true when i is at the last position of the game
        Return true

有关如何前进的任何意见将不胜感激!

1 个答案:

答案 0 :(得分:3)

最重要的一点:在缓慢调试应用时,您应首先收集一些效果数据,以确定您的应用在大部分时间内花费的时间。否则修复性能效率低下。您可以使用与{jdk捆绑在一起的jvisualvm

数据结构统治了绩效世界

为什么它可能会变慢是因为:

if (checkerList.contains(circle)){ // check for the impossible case 
    return false;
}

列表中的项目越多,它就越慢。列表的linear complexity方法为contains。如果您使用constant complexity,则可以HashSet。例如。如果您有包含100个元素的列表,则此部分将使用List比使用HashSet慢100倍。

可能需要一些时间的另一件事是装箱/拆箱:每次将元素放入列表时,int都被包装到新的Integer对象中 - 这称为装箱。您可能希望使用IntSet来避免装箱/取消装箱并节省GC时间。

转换为迭代形式

我不希望这会影响您的申请速度,但仅仅是为了完整答案。

将递归应用程序转换为迭代形式非常简单:封面下的每个方法参数都会在您(或其他函数)的每次调用时存储在隐藏堆栈中。在转换过程中,您只需创建自己的堆栈并手动管理

public static boolean rightWingRecursive(int circle, int[] game) {
    Set<Integer> checkerList = new HashSet<Integer>();
    Deque<Integer> statesToExplore = new LinkedList<>();

    int last = game.length - 1;

    statesToExplore.push(circle);

    while (!statesToExplore.isEmpty()) {
        int circleState = statesToExplore.pop();

        if (circleState == last) { // base case for recursion
            return true;
        }

        if (circleState < 0) { // if we go out of bounds on the left
            continue;
        }

        if (circleState > last) { // if we go out of bounds on the right
            continue;
        }

        if (checkerList.contains(circle)) { // check for the impossible case
            continue;
        }

        checkerList.add(circle); // adds the circle value for the last check to
        // checkerList so we can check for the
        // impossible case
        int moveRight = circle + game[circle]; // these two integers help the
        // game move according to the
        // value of the int at circle
        int moveLeft = circle - game[circle];
        statesToExplore.push(moveRight);
        statesToExplore.push(moveLeft);
    }

    return false;
}