Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/361.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
Java 使用递归回溯时耗尽堆_Java_Algorithm_Recursion_Backtracking - Fatal编程技术网

Java 使用递归回溯时耗尽堆

Java 使用递归回溯时耗尽堆,java,algorithm,recursion,backtracking,Java,Algorithm,Recursion,Backtracking,我目前正在研究递归回溯这个美丽的主题。 我已经尝试过经典的例子,比如从迷宫中寻找最短路径,或者n皇后问题。但我现在正在研究的问题确实让我感到困惑: 实际上,我认为解决一个简单的拼图游戏可能是一个简单的练习: 我有一块大小为n=a*b的电路板,正好有那么多(n)块。 最后,我希望所有的棋子都按照一定的顺序放在棋盘上,它们遵守一定的限制(比如匹配它们的邻居)。相当简单,我想,我想出了以下算法: public board recursiveSolve(Board board, Piece[] piec

我目前正在研究递归回溯这个美丽的主题。 我已经尝试过经典的例子,比如从迷宫中寻找最短路径,或者n皇后问题。但我现在正在研究的问题确实让我感到困惑: 实际上,我认为解决一个简单的拼图游戏可能是一个简单的练习: 我有一块大小为n=a*b的电路板,正好有那么多(n)块。
最后,我希望所有的棋子都按照一定的顺序放在棋盘上,它们遵守一定的限制(比如匹配它们的邻居)。相当简单,我想,我想出了以下算法:

public board recursiveSolve(Board board, Piece[] pieces, int position){
// base case
if(position  == board.getLength())
    return board;
else{ 
    // For each possible piece
    for(int i = 0; i < pieces.length; i++){
        // if the piece is placeable at that position
        // place it and search on recursively
        if(board.isValid(piece[i], position)){
            board.putPiece(pieces[i], position);

            // THIS IS THE FISHY PART!!
            // Now I need to pass a set of pieces to the function recursively 
            // that does not contain the current one (pieces[i])
            // But I fear my (following) approach is too heap-intensive

            Piece[] subPieces = new Piece[pieces.length - 1];

            // fill subPieces with all elements from pieces except from the one 
            // at position i
            for (int j = 0; j < subPieces.length; j++) {
                 if(j >= i)
                     subPieces[j] = pieces[j+1];
                 else
                     subPieces[j] = pieces[j];

            }

            if(recursiveSolve(board, subPieces, position + 1) != null)
                 return board;
            else
                 board.removePiece(position);
        }
    }
    // If this is reached, none of the pieces have worked -> go back
    return null;

}
public board recursiveSolve(board-board,Piece[]pieces,int-position){
//基本情况
if(position==board.getLength())
返回板;
否则{
//对于每个可能的部分
对于(int i=0;i=i)
子部分[j]=件[j+1];
其他的
子部分[j]=件[j];
}
if(递归求解(电路板、子部件、位置+1)!=null)
返回板;
其他的
板。拆卸件(位置);
}
}
//如果达到该值,则所有部件均未工作->返回
返回null;
}
好的,基本上,这个算法做它应该做的-但不幸的是,它只适用于“小”板尺寸(n<100)。 因为如果我有一块10 x 10正方形和100块的板,函数会不断搜索,直到JVM因为堆空间不足而崩溃才结束。 我甚至尝试将eclipse的内存大小限制设置为1.2g,这使函数的工作时间更长,但仍然不够

所以我的问题是:是否有可能优化上述算法,使其适用于n>100的电路板尺寸?我做错了什么?或者我采取了完全错误的方法


非常感谢您提前提供的帮助。

函数式语言将通过采用尾部递归来帮助您节省堆。不幸的是,JVM似乎不支持尾部递归(至少对于Java),请参阅


您可以尝试手动模拟尾部递归。

因为电路板有一种方法可以告诉您工件[i]在某个位置是否有效,所以在继续之前迭代这些位置并尝试该位置的每个(剩余)工件是否更有意义?它不会使用递归(这将解决堆空间问题),但如果您特别追求递归解决方案,则显然不适合

为了更有效地做到这一点,我建议将这些片段放在一个列表中,然后在放置时删除一个片段。类似这样:

List<Piece> remainingPieces = new ArrayList<Piece>(Arrays.asList(pieces));
int numberOfPositions = // I assume you have some way of finding this.
for (int position = 0; position < numberOfPositions; position++) {
    Iterator<Piece> it = remainingPieces.iterator();
    while (it.hasNext()) {
        Piece temp = it.next();
        if (board.isValid(temp, position)) {
            board.putPiece(temp, position);
            it.remove();
            break;
        }
    }
}
List remainingPieces=newarraylist(Arrays.asList(pieces));
int numberOfPositions=//我想你有办法找到这个。
对于(int position=0;position
在初始化新的
size-pieces.length-1数组时,程序中的主要堆用法似乎确实是您怀疑的地方。

请注意,您确实可以在此处节省大量空间,因为您实际上只使用“最深”的集合

如果仍要使用数组,可能需要传递一个额外的参数:
start
,并实现
swap(arr,i,k)
,它交换arr中的第i个和第k个元素,在每个步骤中,而不是分配一个新数组,
交换(片段,开始,i)
,并在递归步骤中传递到新函数
start+1
。请注意,由于始终交换最后一个元素,因此接下来的步骤不关心交换,因为它们位于数组的
start
位置之后。因此,基本上,由于算法从不“回头”,因此交换这些元素不会有任何问题在

应该是这样的:

public board recursiveSolve(Board board, Piece[] pieces, int position,int start){
if(position  == board.getLength())
    return board;
else { 
    //starting from start instead from 0
    for(int i = start; i < pieces.length; i++){
        if(board.isValid(piece[i], position)){
            board.putPiece(pieces[i], position);
            swap(pieces,start,i); //the swap() method I mentioned above        
            //sending start+1:
            if(recursiveSolve(board, subPieces, position + 1,start+1) != null) 
                 return board;
            else
                 board.removePiece(position);
        }
    }
    return null;
}
public board recursiveSolve(board-board,Piece[]pieces,int-position,int-start){
if(position==board.getLength())
返回板;
否则{
//从开始而不是从0开始
for(int i=开始;i

您可能知道回溯算法非常耗时[指数!],因此,即使使用空间优化版本,算法可能会运行很长时间,直到找到答案。

除了语言之外,这应该适用于n>100,没有任何问题。.我在代码中看到一些奇怪的事情,比如你每次构建子块,手动移除电路板上的东西,这应该由ba自动完成也许有你