将递归算法转换为迭代算法的困难

发布于 2024-12-15 01:44:17 字数 2979 浏览 0 评论 0原文

我一直在尝试用javascript实现递归回溯迷宫生成算法。这些是在阅读了此处<的主题的一系列精彩帖子后完成的/a>

虽然该算法的递归版本是显而易见的,但迭代版本让我难住了。

我以为我理解了这个概念,但我的实现显然产生了错误的结果。我一直在试图找出可能导致它的错误,但我开始相信我的问题是由逻辑故障引起的,但当然我不知道在哪里。

我对迭代算法的理解如下:

  • 创建一个堆栈来保存单元状态的表示。

  • 每个表示都保存该特定单元的坐标以及访问相邻单元的方向列表。

  • 当堆栈不为空时,迭代堆栈顶部的方向,测试相邻的单元格。

  • 如果找到有效单元格,则将其放置在堆栈顶部并继续使用该单元格。

这是我的递归实现(注意:按下按键向前迈进): http://jsbin.com/urilan/14

这是我的迭代实现(再次按下按键向前迈进): http://jsbin.com/eyosij/2

感谢您的帮助。

编辑:如果我的问题不清楚,我深表歉意。我将尝试进一步解释我的问题。

运行迭代解决方案时,会发生各种意外行为。首先也是最重要的,该算法在回溯之前不会用尽所有可用选项。相反,当剩下一个有效单元格时,它似乎是随机选择单元格。但总体而言,这种运动似乎并不是随机的。

var dirs = [ 'N', 'W', 'E', 'S' ];
var XD = { 'N': 0, 'S':0, 'E':1, 'W':-1 };
var YD = { 'N':-1, 'S':1, 'E':0, 'W': 0 };


function genMaze(){

var dirtemp = dirs.slice().slice();    //copies 'dirs' so its not overwritten or altered
var path = [];                         // stores path traveled.

var stack = [[0,0, shuffle(dirtemp)]]; //Stack of instances. Each subarray in 'stacks' represents a cell
                                       //and its current state. That is, its coordinates, and which adjacent cells have been
                                       //checked. Each time it checks an adjacent cell a direction value is popped from 
                                       //from the list

while ( stack.length > 0 ) {

  var current = stack[stack.length-1]; // With each iteration focus is to be placed on the newest cell.

  var x = current[0], y = current[1], d = current[2];
  var sLen = stack.length;             // For testing whether there is a newer cell in the stack than the current.
  path.push([x,y]);                    // Store current coordinates in the path

  while ( d.length > 0 ) {
    if( stack.length != sLen ){ break;}// If there is a newer cell in stack, break and then continue with that cell

    else {
      var cd = d.pop();
      var nx = x + XD[ cd ];
      var ny = y + YD[ cd ];

      if ( nx >= 0 && ny >= 0  && nx < w && ny < h && !cells[nx][ny] ){

        dtemp = dirs.slice().slice();
        cells[nx][ny] = 1;
        stack.push( [ nx, ny, shuffle(dtemp) ] ); //add new cell to the stack with new list of directions.
                                                  // from here the code should break from the loop and start again with this latest addition being considered.


      }
    }

  }

  if (current[2].length === 0){stack.pop(); } //if all available directions have been tested, remove from stack


}
return path;
}

我希望这有助于解答您的问题。如果仍然缺少任何物质,请告诉我。

再次感谢。

I've been trying to implement a recursive backtracking maze generation algorithm in javascript. These were done after reading a great series of posts on the topic here

While the recursive version of the algorithm was a no brainer, the iterative equivalent has got me stumped.

I thought I understood the concept, but my implementation clearly produces incorrect results. I've been trying to pin down a bug that might be causing it, but I am beginning to believe that my problems are being caused by a failure in logic, but of course I am not seeing where.

My understanding of the iterative algorithm is as follows:

  • A stack is created holding representations of cell states.

  • Each representation holds the coordinates of that particular cell, and a list of directions to access adjacent cells.

  • While the stack isn't empty iterate through the directions on the top of the stack, testing adjacent cells.

  • If a valid cell is found place it at the top of the stack and continue with that cell.

Here is my recursive implementation ( note: keydown to step forward ): http://jsbin.com/urilan/14

And here is my iterative implementation ( once again, keydown to step forward ): http://jsbin.com/eyosij/2

Thanks for the help.

edit: I apologize if my question wasn't clear. I will try to further explain my problem.

When running the iterative solution various unexpected behaviors occur. First and foremost, the algorithm doesn't exhaust all available options before backtracking. Rather, it appears to be selecting cells at a random when there is one valid cell left. Overall however, the movement doesn't appear to be random.

var dirs = [ 'N', 'W', 'E', 'S' ];
var XD = { 'N': 0, 'S':0, 'E':1, 'W':-1 };
var YD = { 'N':-1, 'S':1, 'E':0, 'W': 0 };


function genMaze(){

var dirtemp = dirs.slice().slice();    //copies 'dirs' so its not overwritten or altered
var path = [];                         // stores path traveled.

var stack = [[0,0, shuffle(dirtemp)]]; //Stack of instances. Each subarray in 'stacks' represents a cell
                                       //and its current state. That is, its coordinates, and which adjacent cells have been
                                       //checked. Each time it checks an adjacent cell a direction value is popped from 
                                       //from the list

while ( stack.length > 0 ) {

  var current = stack[stack.length-1]; // With each iteration focus is to be placed on the newest cell.

  var x = current[0], y = current[1], d = current[2];
  var sLen = stack.length;             // For testing whether there is a newer cell in the stack than the current.
  path.push([x,y]);                    // Store current coordinates in the path

  while ( d.length > 0 ) {
    if( stack.length != sLen ){ break;}// If there is a newer cell in stack, break and then continue with that cell

    else {
      var cd = d.pop();
      var nx = x + XD[ cd ];
      var ny = y + YD[ cd ];

      if ( nx >= 0 && ny >= 0  && nx < w && ny < h && !cells[nx][ny] ){

        dtemp = dirs.slice().slice();
        cells[nx][ny] = 1;
        stack.push( [ nx, ny, shuffle(dtemp) ] ); //add new cell to the stack with new list of directions.
                                                  // from here the code should break from the loop and start again with this latest addition being considered.


      }
    }

  }

  if (current[2].length === 0){stack.pop(); } //if all available directions have been tested, remove from stack


}
return path;
}

I hope that helps clear up the question for you. If it is still missing any substance please let me know.

Thanks again.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

花开柳相依 2024-12-22 01:44:17

我不太擅长 javascript,但我尝试将您的递归代码实现为迭代。您还需要在堆栈上存储 For 索引。所以代码看起来像:

function genMaze(cx,cy) {

    var dirtemp = dirs;    //copies 'dirs' so its not overwritten
    var path = [];                         // stores path traveled.    
    var stack = [[cx, cy, shuffle(dirtemp), 0]];  // we also need to store `for` indexer

    while (stack.length > 0) {

        var current = stack[stack.length - 1]; // With each iteration focus is to be placed on the newest cell.

        var x = current[0], y = current[1], d = current[2], i = current[3];
        if (i > d.length) {
            stack.pop();
            continue;
        }
        stack[stack.length - 1][3] = i + 1; // for next iteration

        path.push([x, y]);    // Store current coordinates in the path
        cells[x][y] = 1;

        var cd = d[i];
        var nx = x + XD[cd];
        var ny = y + YD[cd];

        if (nx >= 0 && ny >= 0 && nx < w && ny < h && !cells[nx][ny]) {

            dtemp = dirs;
            stack.push([nx, ny, shuffle(dtemp), 0]);
        }
    }
    return path;
  }

I'm not very good in javascript, but I try to implement your recursive code to iterative. You need to store For index on stack also. So code look like:

function genMaze(cx,cy) {

    var dirtemp = dirs;    //copies 'dirs' so its not overwritten
    var path = [];                         // stores path traveled.    
    var stack = [[cx, cy, shuffle(dirtemp), 0]];  // we also need to store `for` indexer

    while (stack.length > 0) {

        var current = stack[stack.length - 1]; // With each iteration focus is to be placed on the newest cell.

        var x = current[0], y = current[1], d = current[2], i = current[3];
        if (i > d.length) {
            stack.pop();
            continue;
        }
        stack[stack.length - 1][3] = i + 1; // for next iteration

        path.push([x, y]);    // Store current coordinates in the path
        cells[x][y] = 1;

        var cd = d[i];
        var nx = x + XD[cd];
        var ny = y + YD[cd];

        if (nx >= 0 && ny >= 0 && nx < w && ny < h && !cells[nx][ny]) {

            dtemp = dirs;
            stack.push([nx, ny, shuffle(dtemp), 0]);
        }
    }
    return path;
  }
情绪失控 2024-12-22 01:44:17

这个小代码也有帮助吗?

/**
Examples
var sum = tco(function(x, y) {
  return y > 0 ? sum(x + 1, y - 1) :
         y < 0 ? sum(x - 1, y + 1) :
        x
})
sum(20, 100000) // => 100020
**/

function tco(f) {
  var value, active = false, accumulated = []
  return function accumulator() {
    accumulated.push(arguments)
    if (!active) {
      active = true
      while (accumulated.length) value = f.apply(this, accumulated.shift())
      active = false
      return value
    }
  }
}

积分、解释和更多信息位于 github https://gist.github.com/1697037

上,有好处是不修改代码,因此它也可以应用于其他情况。希望有帮助:)

Does this little code could also help ?

/**
Examples
var sum = tco(function(x, y) {
  return y > 0 ? sum(x + 1, y - 1) :
         y < 0 ? sum(x - 1, y + 1) :
        x
})
sum(20, 100000) // => 100020
**/

function tco(f) {
  var value, active = false, accumulated = []
  return function accumulator() {
    accumulated.push(arguments)
    if (!active) {
      active = true
      while (accumulated.length) value = f.apply(this, accumulated.shift())
      active = false
      return value
    }
  }
}

Credits, explanations ans more infos are on github https://gist.github.com/1697037

Is has the benefit to not modifying your code, so it could be applied in other situations too. Hope that helps :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文