背景:
我正在努力学习算法和java。运行一个320x320,100个试验的网格比非递归的Quick-Union实现快5倍。然而,在大约400x400 (160,000个站点)的网格之上,我有堆栈溢出错误。
我知道java并没有针对尾递归进行优化(更不用说非尾递归了)。然而,我认为有时候可以选择递归算法而不是非递归版本,因为它可以运行得更快,也同样安全。
请记住,我只是在学习这些东西,我的代码可能不是最优的。但是,为了更好地理解我的问题,我将其包括在内。
问题是
当递归算法可以在java应用程序中安全地使用时(假设它比非递归替代算法运行得更快),评估的过程是什么?
递归与联合查找实现的统计数据
(注意: 2x比率就是上一次当前运行时间除以上一次运行时间)
|-----------|-----------|------------|-------------|-------------|
| N | Recursive | Recursive | Quick-Union | Quick-Union |
| (sites) | time | 2x Ratio | time | 2x Ratio |
|===========|===========|============|=============|=============|
| 196 | 35 | | 42 | |
| 400 | 25 | 0.71 | 44 | 1.05 |
| 784 | 45 | 1.80 | 46 | 1.05 |
| 1600 | 107 | 2.38 | 86 | 1.87 |
| 3136 | 48 | 0.45 | 113 | 1.31 |
| 6400 | 75 | 1.56 | 303 | 2.68 |
| 12769 | 183 | 2.44 | 858 | 2.83 |
| 25600 | 479 | 2.62 | 2682 | 3.13 |
| 51076 | 1253 | 2.62 | 8521 | 3.18 |
| 102400 | 4730 | 3.77 | 27256 | 3.20 |
|-----------|-----------|------------|-------------|-------------|递归类
public class PercolateRecur implements Percolation {
// the site has been opened for percolation but is not connected
private final int OPEN = 0;
// the site is not open for percolation (default state)
private final int BLOCKED = -1;
// the matrix that will be percolated. Values default to `BLOCKED = -1`
// two sites that are connected together share the same value.
private int[][] matrix;
// the size of the sides of the matrix (1 to n)
private int size;
// whether water can flow from top to bottom of the matrix
private boolean percolated;
public PercolateRecur(int N) {
percolated = false;
size = N;
initMatrix();
}
/**
* initializes the matrix to default values
*/
private void initMatrix() {
matrix = new int[size+1][size+1];
// open up the top of the matrix
for (int x = 1; x < size+1; x++)
matrix[x][0] = x;
// set all values in matrix to closed
for (int x = 1; x < size+1; x++)
for (int y = 1; y < size+1; y++)
matrix[x][y] = BLOCKED;
}
/**
* indicates site (x,y) is a valid coordinate
* @param x x-portion of x/y coordinate
* @param y y-portion of x/y coordinate
* @return boolean
*/
private boolean isValid(int x, int y) {
return x > 0 && x < size+1 && y > 0 && y < size+1;
}
/**
* returns value of site above (x,y)
* @param x x-portion of x/y coordinate
* @param y y-portion of x/y coordinate
* @return int value
*/
private int above(int x, int y) {
if (y <= 0)
return BLOCKED;
else
return matrix[x][y-1];
}
/**
* returns value of site below (x,y)
* @param x x-portion of x/y coordinate
* @param y y-portion of x/y coordinate
* @return int value
*/
private int below(int x, int y) {
if (y >= size)
return BLOCKED;
else
return matrix[x][y+1];
}
/**
* returns value of site left of (x,y)
* @param x x-portion of x/y coordinate
* @param y y-portion of x/y coordinate
* @return int value
*/
private int left(int x, int y) {
if (x <= 0)
return BLOCKED;
return matrix[x-1][y];
}
/**
* returns value of site right of (x,y)
* @param x x-portion of x/y coordinate
* @param y y-portion of x/y coordinate
* @return int value
*/
private int right(int x, int y) {
if (x >= size)
return BLOCKED;
else
return matrix[x+1][y];
}
/**
* connects (x,y) to open adjacent sites
* @param x x-portion of x/y coordinate
* @param y y-portion of x/y coordinate
*/
private void connect(int x, int y) {
if (isFull(x,y))
return;
if (above(x,y) > OPEN)
matrix[x][y] = above(x, y);
else if (below(x, y) > OPEN)
matrix[x][y] = below(x, y);
else if (left(x, y) > OPEN)
matrix[x][y] = left(x, y);
else if (right(x, y) > OPEN)
matrix[x][y] = right(x, y);
else if (matrix[x][y] == BLOCKED)
matrix[x][y] = OPEN;
}
/**
* recursively connects open sites in same group as (x,y)
* @param x x-portion of x/y coordinate
* @param y y-portion of x/y coordinate
*/
private void expand(int x, int y) {
if (!isFull(x, y))
return;
if (above(x,y) == OPEN)
openWith(x,y-1, matrix[x][y]);
if (below(x,y) == OPEN)
openWith(x,y+1, matrix[x][y]);
if (left(x,y) == OPEN)
openWith(x-1,y, matrix[x][y]);
if (right(x,y) == OPEN)
openWith(x+1,y, matrix[x][y]);
}
/**
* opens a site (x,y) on the matrix
* @param x x-portion of x/y coordinate
* @param y y-portion of x/y coordinate
*/
public void open(int x, int y) {
if (percolated || !isValid(x, y))
return;
connect(x, y);
expand(x, y);
}
/**
* opens a site with given value
* @param x x-portion of x/y coordinate
* @param y y-portion of x/y coordinate
* @param val value of point
*/
private void openWith(int x, int y, int val) {
matrix[x][y] = val;
open(x, y);
}
/**
* Returns whether site (x,y) is open
* @param x x-portion of x/y coordinate
* @param y y-portion of x/y coordinate
* @return true if not blocked
*/
public boolean isOpen(int x, int y) {
return matrix[x][y] > BLOCKED;
}
/**
* Returns whether site (x,y) is full (connected to the top)
* @param x x-portion of x/y coordinate
* @param y y-portion of x/y coordinate
* @return true if is full
*/
public boolean isFull(int x, int y) {
return matrix[x][y] > OPEN;
}
/**
* indicates whether site is blocked (not open)
* @param x x-portion of x/y coordinate
* @param y y-portion of x/y coordinate
* @return true if blocked
*/
public boolean isBlocked(int x, int y) {
return matrix[x][y] == BLOCKED;
}
/**
* indicates whether water can flow from top to bottom of matrix
* @return true if matrix is percolated
*/
public boolean percolates() {
for (int x = 1; x <= size; x++)
if (matrix[x][size] > OPEN)
percolated = true;
return percolated;
}
/**
* prints the matrix to the command line
*/
public void print() {
for (int y = 1; y < size+1; y++) {
System.out.println();
for (int x = 1; x < size+1; x++) {
if (matrix[x][y] == BLOCKED)
System.out.print("XX ");
else if (matrix[x][y] < 10)
System.out.print(matrix[x][y] + " ");
else
System.out.print(matrix[x][y] + " ");
}
}
System.out.println();
}
}发布于 2013-02-17 13:34:28
在Java中实现递归算法的问题之一是Java平台不执行标准的“尾部调用消除”优化。这意味着深度递归需要一个深度堆栈。由于Java线程堆栈不会“增长”,这意味着您很容易发生堆栈溢出。
有两种解决方法:
通过在命令行上使用-Xss选项,或者通过在Thread中显式地提供(更大的)堆栈大小,来增加线程堆栈的大小...至少可以说,这是丑陋的。
在您的情况下,第一个变通方法将为您提供“真正的递归”的度量。第二个...算法将不再是真正的递归,但这是您可以做的,以使递归算法在Java中实用于“深度”问题。
注意:您始终可以将Java中的递归算法转换为等效的迭代算法,该算法使用“模拟堆栈”数据结构来保存递归状态。两个版本的算法复杂度应该相同。也许您也应该尝试这种方法,并将“模拟堆栈”变体作为第三对列包含在您的评估中。
https://stackoverflow.com/questions/14917925
复制相似问题