Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/362.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.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 - Fatal编程技术网

Java中的高级递归

Java中的高级递归,java,algorithm,recursion,Java,Algorithm,Recursion,我就是搞不懂递归的诀窍,尤其是复杂的例子。如果有人能花点时间解释一下,我将不胜感激。我有4张纸,上面都写着我在跟踪这个函数,但我不知道如何把它放在一起 public static String shortestPath(int x, int y, int tX, int tY,boolean blocked[][]) { if(x>blocked.length-1 || y>blocked[0].length-1 || x<0 || y<0 )

我就是搞不懂递归的诀窍,尤其是复杂的例子。如果有人能花点时间解释一下,我将不胜感激。我有4张纸,上面都写着我在跟踪这个函数,但我不知道如何把它放在一起

public static String shortestPath(int x, int y, int tX, int tY,boolean blocked[][]) {

        if(x>blocked.length-1 || y>blocked[0].length-1 || x<0 || y<0 )
            return null;
        if(blocked[x][y]==true)
            return null;
        if(x==tX && y==tY)
            return "";

        String paths[]=new String[4];
        blocked[x][y]=true; //this just means this coordinate is blocked, so dont use it
        paths[0]=shortestPath(x, y+1, tX, tY, blocked);
        paths[1]=shortestPath(x, y-1, tX, tY, blocked);
        paths[2]=shortestPath(x+1, y, tX, tY, blocked);
        paths[3]=shortestPath(x-1, y, tX, tY, blocked);
        blocked[x][y] = false;
        int result=findShortestString(paths, 0, 3); 
//findShortestString just takes an array of strings, 
//with 0 being the lo index and 3 being the hi, 
//and returns the index that contains the string with the shortest length.
        //5
        if(paths[result]==null)
           return null;
        else{

           if(result==0)
                return 'N' + paths[result];
           if(result==1)
                return 'S' + paths[result];
           if(result==2)
                return 'E' + paths[result];
           if(result==3)
                return 'W' + paths[result];}

        return paths[result];
因此,这段代码的作用是,给定一个x和y参数,它告诉你,为了达到tX和tY参数,你必须进行北、南、西、东的NSWE移动的最短组合。代码运行得很好,但我不知道如何运行


当我试图跟踪路径[0]计算的内容时,它总是显示为null,因为y总是不断递增,直到它超出界限为止,在这个界限中它返回null。路径[1][2]和[3]的情况也是如此,它们都返回null,不是吗?那么这个函数到底是如何工作的呢?

首先用一个很小的例子来尝试它——一个没有阻塞单元格的1x1网格。正如预期的那样,没有任何行动可以采取。x==tX和y==tY,所以返回空字符串。到目前为止还不错

现在看一个2x2的网格,你在西北角,目的地是东北

| @ | ^ |
| o | o |
当您尝试向东移动并设置路径[0]时,它会调用最短路径,阻塞当前单元格并将新位置设置为您下方的位置。现在你有了

| X | ^ |
| @ | o |
在该调用中,它将尝试去N、W、s和E。为简单起见,忽略向东发生在向西之前,因此我们可以立即完成其他3个方向-它们都再次调用无效位置上的最短路径2越界,1您已经到达,并立即返回null。您将带着一个新的网格和位置向东移动,如下所示:

| X | ^ |
| X | @ |
| X | @^ |
| X | X  |
同样,其中3个方向返回null。只有北方会给你你想要的最终结果。当您尝试去那里时,您再次调用shortestPath,它立即返回空字符串,因为电路板现在看起来如下所示:

| X | ^ |
| X | @ |
| X | @^ |
| X | X  |
现在我们来总结一下调用堆栈:

因为路径[1]是空字符串,而其他3个路径是空字符串,所以结果是1,我假设字符串函数就是这样工作的。因此,返回N到上一个调用。 上一次调用将显示路径[0]==null,路径[1]==null,路径[3]==null,但关键路径[2]是N。因此结果将是2,您将返回EN到前面的调用。 既然现在你回到了最短路径的第一次调用,那就结束了我们的第一个选择——从起始位置往南走。但我们还有一个选择——向东走。所以你跟着那棵树走,它很简单

然后是最后一步,在这里你可以看到哪个字符串更小,得到的字符串当然比EN小。结果是2,所以你在字符串前面加上E,E是你的最终答案


现在用它来找出更大的例子。它有助于绘制决策树和每个节点的电路板状态。当你到达叶子时,画箭头返回到表示返回值的父节点。这将非常有帮助。

首先用一个很小的例子来尝试它——一个没有阻塞单元的1x1网格。正如预期的那样,没有任何行动可以采取。x==tX和y==tY,所以返回空字符串。到目前为止还不错

现在看一个2x2的网格,你在西北角,目的地是东北

| @ | ^ |
| o | o |
当您尝试向东移动并设置路径[0]时,它会调用最短路径,阻塞当前单元格并将新位置设置为您下方的位置。现在你有了

| X | ^ |
| @ | o |
在该调用中,它将尝试去N、W、s和E。为简单起见,忽略向东发生在向西之前,因此我们可以立即完成其他3个方向-它们都再次调用无效位置上的最短路径2越界,1您已经到达,并立即返回null。您将带着一个新的网格和位置向东移动,如下所示:

| X | ^ |
| X | @ |
| X | @^ |
| X | X  |
同样,其中3个方向返回null。只有北方会给你你想要的最终结果。当您尝试去那里时,您再次调用shortestPath,它立即返回空字符串,因为电路板现在看起来如下所示:

| X | ^ |
| X | @ |
| X | @^ |
| X | X  |
现在我们来总结一下调用堆栈:

因为路径[1]是空字符串,而其他3个路径是空字符串,所以结果是1,我假设字符串函数就是这样工作的。因此,返回N到上一个调用。 上一次调用将显示路径[0]==null,路径[1]==null,路径[3]==null,但关键路径[2]是N。因此结果将是2,您将返回EN到前面的调用。 既然现在你回到了最短路径的第一次调用,那就结束了我们的第一个选择——从起始位置往南走。但我们还有一个选择——向东走。所以你跟着那棵树走,它很简单

然后是最后一步,在这里你可以看到哪个字符串更小,得到的字符串当然比EN小。结果是2,所以你在字符串前面加上E,E是你的最终答案

现在用它来计算大的
r示例。它有助于绘制决策树和每个节点的电路板状态。当你到达叶子时,画箭头返回到表示返回值的父节点。这将非常有帮助。

试着猜你在想什么-

您可能正在描绘4条执行路径:

路径0:shortestPathx,y+1,tX,tY,blocked->shortestPathx,y+1,tX,tY,blocked->

路径1:shortestPathx,y-1,tX,tY,blocked->shortestPathx,y-1,tX,tY,blocked->

路径2:最短路径X+1,y,tX,tY,阻塞->最短路径X+1,y,tX,tY,阻塞->

路径3:最短路径X-1,y,tX,tY,阻塞->最短路径X-1,y,tX,tY,阻塞->

实际上,执行路径是一棵树。对shortestPath的每次调用都会产生对shortestPath的4个调用、一个path0调用、一个path1调用、一个path2调用和一个path3调用

因此,您将得到一个执行路径,即path0,path0,path0。。。这将返回null

但是,大多数路径将是不同调用的组合


当递归返回到第一个最短路径调用时,路径[0]将包含第一次移动为最短路径x、y+1、tX、tY、blocked的最短路径,路径[1]第一次移动为最短路径x、y-1、tX、tY、blocked等的最短路径。

尝试猜测您的想法-

您可能正在描绘4条执行路径:

路径0:shortestPathx,y+1,tX,tY,blocked->shortestPathx,y+1,tX,tY,blocked->

路径1:shortestPathx,y-1,tX,tY,blocked->shortestPathx,y-1,tX,tY,blocked->

路径2:最短路径X+1,y,tX,tY,阻塞->最短路径X+1,y,tX,tY,阻塞->

路径3:最短路径X-1,y,tX,tY,阻塞->最短路径X-1,y,tX,tY,阻塞->

实际上,执行路径是一棵树。对shortestPath的每次调用都会产生对shortestPath的4个调用、一个path0调用、一个path1调用、一个path2调用和一个path3调用

因此,您将得到一个执行路径,即path0,path0,path0。。。这将返回null

但是,大多数路径将是不同调用的组合


当递归返回到第一个最短路径调用时,路径[0]将包含第一次移动为最短路径x、y+1、tX、tY、blocked的最短路径,路径[1]第一次移动为最短路径x、y-1、tX、tY、blocked等的最短路径。

没有那么复杂

该部分检查x或y参数是否在边界内有效或未被阻止

if(x>blocked.length-1 || y>blocked[0].length-1 || x<0 || y<0 )
   return null;
if(blocked[x][y]==true)
   return null;
现在转到递归部分,该函数递归到其他四个函数中,每个函数相对于当前位置有一个可用的NSWE方向:

String paths[]=new String[4];
blocked[x][y]=true; //this just means this coordinate is blocked, so dont use it
paths[0]=shortestPath(x, y+1, tX, tY, blocked);
paths[1]=shortestPath(x, y-1, tX, tY, blocked);
paths[2]=shortestPath(x+1, y, tX, tY, blocked);
paths[3]=shortestPath(x-1, y, tX, tY, blocked);
blocked[x][y] = false;
int result=findShortestString(paths, 0, 3);
然后比较递归函数找到的每个路由,以找到可用的最短路径/方向串

如果每个字符串都为null,FindShortString可能返回null,因此无法从该递归的起始位置到达目标

递归的当前位置被标记为阻塞,因此算法不会返回到以前访问过的位置

if(paths[result]==null)
    return null;
这将检查FindShortString是否未找到任何有效路径

最后,相对于递归中当前位置找到的路径被附加到找到最短路径的递归调用的方向上

例如: 假设一张地图只有一条到目的地的有效路径,所有其他位置都会被阻塞。起始位置为[0][0],目的地为[1][1]x+1=N,y+1=E 地图:

第一个电话:

-x,y are within boundaries and are not the destination
-blocks current positions([0][0])
-calls function for y = y+1 -> is blocked (returns NULL)
-calls function for y = y-1 -> out of boundaries (returns NULL)
-calls function for x = x+1 -> path is ok
递归:

-blocks current position[1][0]
-calls function for y = y+1 -> Destination!(returns "")
-calls function for y = y-1 -> out of boundaries(returns NULL)
-calls function for x = x+1 -> out of boundaries(returns NULL)
-calls function for x = x-1 -> blocked(returns NULL) (this would be the starting position)
Since paths[0] has the shortest string("") and the result is 'N'+""
回到第一次迭代

-calls function for x = x-1 -> out of boundaries(returns NULL)
由于路径[2]的字符串最短,因此结果为“E”+“N”。这是正确的


由于总是首先调用y=y+1,因此递归将一直运行到超出边界。然后它将测试最后一个位置周围的其他位置,依此类推。

这并不复杂

该部分检查x或y参数是否在边界内有效或未被阻止

if(x>blocked.length-1 || y>blocked[0].length-1 || x<0 || y<0 )
   return null;
if(blocked[x][y]==true)
   return null;
现在转到递归部分,该函数递归到其他四个函数中,每个函数相对于当前位置有一个可用的NSWE方向:

String paths[]=new String[4];
blocked[x][y]=true; //this just means this coordinate is blocked, so dont use it
paths[0]=shortestPath(x, y+1, tX, tY, blocked);
paths[1]=shortestPath(x, y-1, tX, tY, blocked);
paths[2]=shortestPath(x+1, y, tX, tY, blocked);
paths[3]=shortestPath(x-1, y, tX, tY, blocked);
blocked[x][y] = false;
int result=findShortestString(paths, 0, 3);
然后比较递归函数找到的每个路由,以找到可用的最短路径/方向串

如果每个字符串都为null,FindShortString可能返回null,因此无法从该递归的起始位置到达目标

递归的当前位置被标记为阻塞,因此算法不会返回到以前访问过的位置

if(paths[result]==null)
    return null;
这将检查FindShortString是否未找到任何有效路径

最后,相对于递归中当前位置找到的路径被附加到找到最短路径的递归调用的方向上

例如: 假设一张地图只有一条到目的地的有效路径,所有其他位置都会被阻塞。起始位置为[0][0],目的地为[1][1]x+1=N,y+1=E 地图:

第一个电话:

-x,y are within boundaries and are not the destination
-blocks current positions([0][0])
-calls function for y = y+1 -> is blocked (returns NULL)
-calls function for y = y-1 -> out of boundaries (returns NULL)
-calls function for x = x+1 -> path is ok
递归:

-blocks current position[1][0]
-calls function for y = y+1 -> Destination!(returns "")
-calls function for y = y-1 -> out of boundaries(returns NULL)
-calls function for x = x+1 -> out of boundaries(returns NULL)
-calls function for x = x-1 -> blocked(returns NULL) (this would be the starting position)
Since paths[0] has the shortest string("") and the result is 'N'+""
回到第一次迭代

-calls function for x = x-1 -> out of boundaries(returns NULL)
由于路径[2]的字符串最短,因此结果为“E”+“N”。这是正确的


由于总是首先调用y=y+1,因此递归将一直运行到超出边界。然后它将测试最后一个位置周围的其他位置,依此类推。

谢谢,伙计,这真的很有帮助。你/任何人有关于递归的好读物吗?谢谢,伙计,这真的很有帮助。你/任何人对递归有什么好的理解吗?可能的重复