StackOverflow 错误:如何避免它或将此 DFS 转变为迭代 DFS?
我正在使用深度优先搜索来生成迷宫。
使用DFS以随机顺序遍历M*N顶点的邻接矩阵,我只对生成随机路线感兴趣。
这个东西在顶点数量减少的情况下工作得很好,但是当我将它与
Graph theGraph = new Graph(1000,1000);
问题一起使用时,我遇到了 StackOverflow 异常: a)如何使用堆栈将此递归调用更改为迭代调用?
b) 有没有办法为方法调用堆栈分配更多内存?
class IJ {
int i;
int j;
IJ (int i,int j){
i = this.i;
j= this.j;
}
}
class Graph {
int M;
int N;
int adjacencyMatrix[][];
ArrayList <IJ> orderOfVisits;
Graph(int M,int N){
this.M=M;
this.N=N;
adjacencyMatrix=new int[M][N];
for (int i=0; i<M; i++)
for (int j=0;j<N;j++){
adjacencyMatrix[i][j]=-1; //mark all vertices as not visited
}
orderOfVisits = new ArrayList<IJ>();
}
void DFS(int i, int j){ // i,j identifies the vertex
boolean northValid= false;
boolean southValid= false;
boolean eastValid = false;
boolean westValid = false;
int iNorth, jNorth;
int iSouth, jSouth;
int iEast, jEast;
int iWest, jWest;
iNorth=i-1;
if (!(iNorth<0)) northValid=true;
iSouth=i+1;
if(!((iSouth)>=M)) southValid=true;
jEast=j+1;
if(!((jEast)>=N)) eastValid=true;
jWest= j-1;
if (!(jWest<0)) westValid=true;
if (adjacencyMatrix[i][j]==-1){ //if the vertex is unvisited
adjacencyMatrix[i][j]=0; //mark the vertex as visited
IJ ij = new IJ(i,j);
orderOfVisits.add(ij); //add the vertex to the visit list
System.out.println("Visit i,j: " + i +" " +j);
Double lottery = Math.random();
for (int rows=i; rows<M; rows++)
for (int cols=j; cols<N; cols++){
if (lottery>0.75D){
if(northValid)
{
DFS(iNorth,j);
}
if(southValid){
DFS(iSouth,j);
}
if(eastValid){
DFS(i, jEast);
}
if(westValid){
DFS(i,jWest);
}
}
else if (lottery<0.25D)
{
if(westValid){
DFS(i,jWest);
}
if(eastValid){
DFS(i, jEast);
}
if(southValid){
DFS(iSouth,j);
}
if(northValid)
{
DFS(iNorth,j);
}
}
else if ((lottery>=0.25D)&&(lottery<0.5D))
{
if(southValid){
DFS(iSouth,j);
}
if(eastValid){
DFS(i, jEast);
}
if(westValid){
DFS(i,jWest);
}
if(northValid){
DFS(iNorth,j);
}
}
else if ((lottery>=0.5D)&&(lottery<=0.75D))
{
if(eastValid){
DFS(i, jEast);
}
if(westValid){
DFS(i,jWest);
}
if(southValid){
DFS(iSouth,j);
}
if(northValid){
DFS(iNorth,j);
}
}
}
} //end nested for
} //end DFS
//
}
public class Main {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
Graph theGraph = new Graph(1000,1000);
theGraph.DFS(0,0);
}
}
I'm using Depth First Search for maze generation.
The adjacency matrix of M*N vertices is traversed in a random order using DFS, I'm only interested in generating a random route.
The thing works fine with a reduced number of vertices, but I'm getting a StackOverflow Exception when using it with
Graph theGraph = new Graph(1000,1000);
Questions:
a)How can I change this recursive calls to iterative ones using a stack?
b)Is there a way to assign more memory to the method call stack?
class IJ {
int i;
int j;
IJ (int i,int j){
i = this.i;
j= this.j;
}
}
class Graph {
int M;
int N;
int adjacencyMatrix[][];
ArrayList <IJ> orderOfVisits;
Graph(int M,int N){
this.M=M;
this.N=N;
adjacencyMatrix=new int[M][N];
for (int i=0; i<M; i++)
for (int j=0;j<N;j++){
adjacencyMatrix[i][j]=-1; //mark all vertices as not visited
}
orderOfVisits = new ArrayList<IJ>();
}
void DFS(int i, int j){ // i,j identifies the vertex
boolean northValid= false;
boolean southValid= false;
boolean eastValid = false;
boolean westValid = false;
int iNorth, jNorth;
int iSouth, jSouth;
int iEast, jEast;
int iWest, jWest;
iNorth=i-1;
if (!(iNorth<0)) northValid=true;
iSouth=i+1;
if(!((iSouth)>=M)) southValid=true;
jEast=j+1;
if(!((jEast)>=N)) eastValid=true;
jWest= j-1;
if (!(jWest<0)) westValid=true;
if (adjacencyMatrix[i][j]==-1){ //if the vertex is unvisited
adjacencyMatrix[i][j]=0; //mark the vertex as visited
IJ ij = new IJ(i,j);
orderOfVisits.add(ij); //add the vertex to the visit list
System.out.println("Visit i,j: " + i +" " +j);
Double lottery = Math.random();
for (int rows=i; rows<M; rows++)
for (int cols=j; cols<N; cols++){
if (lottery>0.75D){
if(northValid)
{
DFS(iNorth,j);
}
if(southValid){
DFS(iSouth,j);
}
if(eastValid){
DFS(i, jEast);
}
if(westValid){
DFS(i,jWest);
}
}
else if (lottery<0.25D)
{
if(westValid){
DFS(i,jWest);
}
if(eastValid){
DFS(i, jEast);
}
if(southValid){
DFS(iSouth,j);
}
if(northValid)
{
DFS(iNorth,j);
}
}
else if ((lottery>=0.25D)&&(lottery<0.5D))
{
if(southValid){
DFS(iSouth,j);
}
if(eastValid){
DFS(i, jEast);
}
if(westValid){
DFS(i,jWest);
}
if(northValid){
DFS(iNorth,j);
}
}
else if ((lottery>=0.5D)&&(lottery<=0.75D))
{
if(eastValid){
DFS(i, jEast);
}
if(westValid){
DFS(i,jWest);
}
if(southValid){
DFS(iSouth,j);
}
if(northValid){
DFS(iNorth,j);
}
}
}
} //end nested for
} //end DFS
//
}
public class Main {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
Graph theGraph = new Graph(1000,1000);
theGraph.DFS(0,0);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
一些伪代码:
基本上:
我不认为增加堆栈限制是一个很好的解决方案你的问题。
Some pseudo code:
Basically:
I don't think increasing your stack limit is a good solution to your problem.
对于 (b),至少对于 Sun/Oracle JVM,您可以使用 JVM 的
-Xss
命令行选项来增加堆栈大小。With respect to (b), at least with a Sun/Oracle JVM, you can increase the stack size with the
-Xss
command line option to the JVM.您必须将递归实现转换为迭代实现。通常(我也认为这里)递归算法比做同样事情的迭代算法更容易理解。
原则上,您需要用包含必要信息的显式数据结构(堆栈等)来替换 Java 方法调用堆栈。
在您的情况下,它将是当前节点,以及要访问的剩余邻居节点的列表(按应访问的顺序排列)。
visitNode
将包含主要逻辑,即 DFS 方法中现在的内容。它不会递归,而是按照由random()
结果确定的顺序,用四个方向中的一些(我认为最多 3 个)填充队列。You would have to convert the recursive implementation to an iterative one. Often (and I think here, too) a recursive algorithm is a lot easier to understand than an iterative one doing the same things.
In principle, you need to replace the Java method calling stack with an explicit data structure (a stack or such) containing the necessary information.
In your case it would be the current node, and a list of the remaining neighbor nodes to be visited, in the order they should be visited.
The
visitNode
would contain the main logic, i.e. what is now in your DFS method. Instead of recursing it would fill the queue with some of the four directions (at most 3, I think), in a order determined by therandom()
result.我希望您会发现这很有帮助。
您可以使用 -Xss 选项增加堆栈大小或重写代码。您可以在这里得到一些想法。
http://www.vvlasov.com/2013/07 /post-order-iterative-dfs-traversal.html
代码:
public void dfsPostOrderIterative(AdjGraph graph, AdjGraph.Node vertex,回调回调){
访问堆栈 = new Stack();
toVisit.push(new Level(Collections.singletonList(vertex)));
}
I hope you'll find this helpfull.
You can either increase Stack size with -Xss option or rewrite the code. You can get some ideas here.
http://www.vvlasov.com/2013/07/post-order-iterative-dfs-traversal.html
Code:
public void dfsPostOrderIterative(AdjGraph graph, AdjGraph.Node vertex, Callback callback) {
Stack toVisit = new Stack();
toVisit.push(new Level(Collections.singletonList(vertex)));
}