Arrays 返回函数返回到main而不是调用者

Arrays 返回函数返回到main而不是调用者,arrays,recursion,parameters,return,main,Arrays,Recursion,Parameters,Return,Main,只是想知道 void mazeTraversal(char maze[12][12], int x, int y) { if (maze[x + 1][y] == '.') mazeTraversal(maze, ++x, y); if (maze[x][y + 1] == '.') mazeTraversal(maze, x, ++y); if (maze[x - 1][y] == '.') mazeTraversal(maze, --x, y); if (maze[x

只是想知道

void mazeTraversal(char maze[12][12], int x, int y)
{
if (maze[x + 1][y] == '.')
    mazeTraversal(maze, ++x, y);
if (maze[x][y + 1] == '.')
    mazeTraversal(maze, x, ++y);
if (maze[x - 1][y] == '.')
    mazeTraversal(maze, --x, y);
if (maze[x][y - 1] == '.')
    mazeTraversal(maze, x, --y);
   return;
}

当我遇到死胡同时,我是否应该返回到调用的前一个实例,而不是直接返回到主函数?如果我有什么不对劲,请告诉我。

正如你现在所做的那样,当你遇到死胡同时,你就回来。这是正确的,因为您将返回到上一个调用,然后选择下一个路径。当您遍历所有可能的路径后,您的顶级调用将返回。

使用返回值捕获“正确路径”信息并提供。然而,原始代码的另一个关键问题是使用
++/--
,这会对相应的变量产生副作用。由于这个原因,下面的代码避开了这些操作符


实现这一点的主要方法是返回一个值,例如,如果此路径指向,则返回true,否则返回end或false

一个非常原始的转换将如下所示。注意基本情况的添加-这意味着我们可以停止递归。返回True,以便前一个调用方也知道他们可以停止查找,并且函数堆栈将很快展开回到“main”

请注意,我删除了
++/--
以避免奇怪的副作用

但是,我们可以做得更好,并清理一些代码。关键的区别在于每个递归调用都会检查当前位置,而不是它的邻居的位置

bool mazeTraversal(char maze[12][12], int x, int y) {
  if (maze[x][y] == 'X')
    return true; // found end!

  if (maze[x][y] == '.') {
    // we are still on a path - see where exploration leads!
    if (mazeTraversal(maze, x + 1, y)) return true;
    if (mazeTraversal(maze, x, y + 1)) return true;
    if (mazeTraversal(maze, x - 1, y)) return true;
    if (mazeTraversal(maze, x, y - 1)) return true;
  }

  // Didn't find any valid path from here -
  // maybe "here" is a wall!
  return false;
}
最终,您可能希望在找到的路径上执行其他操作(即,在该路径上显示“return true”),例如记录当前位置

还要注意的是,根据语言的不同,
if(mazeTraversal..)返回true
内容也可以“清理”。在C中,考虑使用短路<代码> < <代码> >运算符。然后我们可以将最终案例缩短为:

int leadsToEnd =
       (maze[x][y] == 'X')      // at end
    || (maze[x][y] == '.')      // or not end ..
       && (mazeTraversal(maze, x + 1, y)   // but may lead to end
           || mazeTraversal(maze, x, y + 1)
           || mazeTraversal(maze, x - 1, y) 
           || mazeTraversal(maze, x, y - 1));

因此,整个函数实际上变成了
return leadsToEnd
(根据需要替换上述表达式)。当然,您必须决定哪种方法(后一个示例可能过于聪明)或混合使用哪种方法对您最有意义。

“我是否应该回到调用的前一个实例”您的意思是什么?这是什么语言?@user2646981您使用的编译标志是什么?这可能是因为您得到了逐尾递归优化吗?(另外,如果您使用的是C,请将其标记为C)@DennisMeng在gcc中默认情况下它们是开着的吗?如果没有,我对此表示怀疑。我只有调试和汇编输出选项。在这种情况下,您在汇编中看到了什么?如果它在做一些出乎意料的优化,那将是一种找到外卖的方法,你看,它实际上又回到了主要方面:这就是让我困惑的地方。我还假设它会像逻辑上假设递归那样堆叠起来,但是…它的返回几乎是一个转到主。。。附言:这是最复杂的方法,但它是有效的。太棒了…非常感谢你。然而,我仍然不明白为什么我的方法不起作用…我知道无效类型是好的,不是实际值,但我会假设一个无效函数仍然会像一个正常函数一样返回…谢谢你…尽管如此,只是出于教育目的…你能解释为什么我最初的方法不起作用吗?我复制了你的方法(用int替换bool)它工作得非常好。但是,仍然有问题:1)我没有包含基本情况,我理解,但是当说return时,它不应该返回调用函数吗?假设我使用了第一个条件语句,调用了函数,然后发现它是一个ead end。当我在被调用函数中找到return语句时,它不应该返回到调用方,而不是返回到main吗?2) 递增和递减会产生什么副作用?我已经更新了一些答案。还可以看到维基百科递归文章的链接,以及基本案例。哇……我刚刚意识到。增量导师永久更改变量。我可能会在那里加上x=x+1。这样一个小错误……至少现在我的原始代码可以工作了(当它到达迷宫的出口时,我添加了一个基本案例)。谢谢你提到那个错误
int leadsToEnd =
       (maze[x][y] == 'X')      // at end
    || (maze[x][y] == '.')      // or not end ..
       && (mazeTraversal(maze, x + 1, y)   // but may lead to end
           || mazeTraversal(maze, x, y + 1)
           || mazeTraversal(maze, x - 1, y) 
           || mazeTraversal(maze, x, y - 1));