我遇到了一些stackoverflow问题,希望有人可以让我对非递归解决方案有所了解。
Ident[][] map = ...
private int explore(Ident item, int xcoord, int ycoord) {
if ((map[xcoord][ycoord] == null) || !map[xcoord][ycoord].equals(item))
return 0;
map[xcoord][ycoord] = null;
int sumX, sumY, counter = 1;
item.translate(xcoord, ycoord);
for (int y = -1; y <= 1; y++)
for (int x = -1; x <= 1; x++) {
sumX = x + xcoord;
sumY = y + ycoord;
if (((y != 0) || (x != 0)) && (sumX >= 0) && (sumX < map.length) &&
(sumY >= 0) && (sumY < map.[0].length))
counter += explore(item, sumX, sumY);
}
}
}
return counter;
}
该方法给出了一个Ident对象的二维数组,一个目标Ident和一个数组内的起始位置。它以递归方式遍历数组 计算Ident占据的连续区域的大小。它还将输入的Ident项目集中在该区域的中间。
通过遍历map数组并在任何非null元素上调用explore方法,我可以构建一个以其区域为中心的Ident项数组,并且相对于它们的区域具有大小。
可以看到除了小地图以外的任何东西,堆栈都会溢出。
任何人都有另一种方法来完成同样的任务吗?还是有些见解可以帮我找到一个?
答案 0 :(得分:2)
要消除递归,请在其包含任何项目时创建要探索和循环的坐标列表;在你的循环中,构建一个新的坐标列表进行探索,在循环结束时,用新列表替换旧列表。
答案 1 :(得分:1)
这让我回到80年代中期。任何泛洪填充算法都需要一定量的状态。遗憾的是我不记得算法了。大范围的效率可能不会对迷宫有效。
为了避免递归而不是递归,只需将您调用的数据添加到堆栈中。循环从堆栈顶部弹出下一个未探测的坐标。使用堆栈而不是FIFO队列可以稍微改善一下位置,虽然它可能不会在这里产生巨大的差异。
private int explore(Ident item, int xcoord, int ycoord) {
int counter = 0;
Queue<Point> stack = Collections.asLifoQueue(new ArrayDeque<Point>());
stack.add(new Point(xcoord, ycoord));
while (!stack.isEmpty()) {
Point point = stack.remove();
xcoord = point.x;
ycoord = point.y;
if (!item.equals(map[xcoord][ycoord])) {
continue;
}
++counter;
map[xcoord][ycoord] = null;
item.translate(xcoord, ycoord);
for (int y = -1; y <= 1; y++)
for (int x = -1; x <= 1; x++) {
int sumX = x + xcoord;
int sumY = y + ycoord;
if (
!(x == 0 && y == 0) &&
0 <= sumX && sumX < map.length &&
0 <= sumY && sumY < map[0].length
) {
stack.add(new Point(sumX, sumY));
}
}
}
}
return counter;
}
在stackoverflow的最佳传统中,这还没有看到编译器。 (它也保留了原始算法的大部分内容。)