如何在Java中评估递归算法的效用?
背景:
我正在尝试学习算法和java.运行320×320的网格,100次试验比非递归的Quick-Union实施快5倍.但是,超过大约400×400(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) == OPEN) openWith(x,y-1,matrix[x][y]); if (below(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,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(); } } 解决方法
在Java中实现递归算法的一个问题是Java平台不执行标准的“尾调用消除”优化.这意味着深度递归需要深度堆栈.而且由于Java线程堆栈没有“增长”,这意味着您很容易受到堆栈溢出的影响.
有两种解决方法: >通过在命令行上使用-Xss选项或通过在Thread构造函数中显式提供(更大)堆栈大小来增加线程堆栈大小. 在您的情况下,第一个解决方法将为您提供“真正的递归”的度量.第二个……那么算法将不再是真正的递归,但这就是你可以做的一个使用Java实现“深度”问题的递归算法. 注意:您始终可以将Java中的递归算法转换为使用“模拟堆栈”数据结构来保持递归状态的等效迭代算法.两个版本的算法复杂度应该相同.也许您应该尝试这种方法,并在评估中将“模拟堆栈”变体包含为第三对列. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |