【问题标题】:Difficulties in converting an recursive algorithm into an iterative one将递归算法转换为迭代算法的困难
【发布时间】:2011-11-11 05:03:56
【问题描述】:

我一直在尝试在 javascript 中实现递归回溯迷宫生成算法。这些是在阅读了关于主题here的一系列精彩帖子后完成的@

虽然该算法的递归版本很简单,但 iterative equivalent 让我很困惑。

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

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

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

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

  • 虽然堆栈不是空的,但迭代堆栈顶部的方向,测试相邻的单元格。

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

这是我的递归实现(注意:keydown 前进):http://jsbin.com/urilan/14

这是我的迭代实现(再次,keydown 向前一步):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;
}

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

再次感谢。

【问题讨论】:

  • 您能否在问题中包含代码的相关部分? (并明确说明您的实际问题,冒着被关闭的风险)
  • @MizardX 我已经进行了更改。我希望他们能解决你提到的问题。感谢您的帮助。

标签: javascript algorithm recursion maze


【解决方案1】:

我不是很擅长 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;
  }

【讨论】:

  • 感谢您的回复。我实际上得到了它的工作,但解决方案与您的不同。老实说,我不确定为什么我的解决方案有效,呵呵。但我试过你的,它确实有效。我注意到的一件事是,每次移动时,它似乎在每个单元格处停了两次,放慢了速度。谢谢!如果您有兴趣,这是我的解决方案:jsbin.com/uvahey/edit#preview。再次感谢!
【解决方案2】:

这个小代码也有帮助吗?

/**
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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-13
    相关资源
    最近更新 更多