【问题标题】:How to debug a recursive function in JS如何在 JS 中调试递归函数
【发布时间】:2020-03-05 15:26:32
【问题描述】:

我编写了以下递归代码,用于解决数独难题。

grid:一个全局矩阵,代表拼图。
可能的功能:为给定的数字和位置返回真或假
解决:填充网格的递归。

但是我有一个错误,我怎样才能在不陷入死循环的情况下调试它。

是否有某种强制退出? 你能发现错误吗?

let grid = [
  [5, 3, 0, 0, 7, 0, 0, 0, 0],
  [6, 0, 0, 1, 9, 5, 0, 0, 0],
  [0, 9, 8, 0, 0, 0, 0, 6, 0],
  [8, 0, 0, 0, 6, 0, 0, 0, 3],
  [4, 0, 0, 8, 0, 3, 0, 0, 1],
  [7, 0, 0, 0, 2, 0, 0, 0, 6],
  [0, 6, 0, 0, 0, 0, 2, 8, 0],
  [0, 0, 0, 4, 1, 9, 0, 0, 5],
  [0, 0, 0, 0, 8, 0, 0, 7, 9]];

function possible(x, y, n) {
  for (let i = 0; i < 9; i++) {
    if (grid[y][i] === n) {
      return false
    }
  }
  for (let i = 0; i < 9; i++) {
    if (grid[i][x] === n) {
      return false
    }
  }
  let x0 = Math.floor(x / 3) * 3;
  let y0 = Math.floor(y / 3) * 3;
  for (let i = 0; i < 3; i++) {
    for (let j = 0; j < 3; j++) {
      if (grid[y0 + i][x0 + j] === n) {
        return false
      }
    }
  }
  return true;
}

function solve() {
  for (let y = 0; y < 9; y++) {
    for (let x = 0; x < 9; x++) {
      if (grid[y][x] === 0) {
        for (let n = 1; n < 10; n++) {
          if(possible(y,x,n)){
            grid[y][x] = n;
            solve();
            grid[y][x] = 0;
          }
        }
        return;
      }
    }
  }
}

solve();

【问题讨论】:

  • debugger?取决于您的环境。
  • 我不认为这里有错误的递归,而只是一个非常大的问题空间来递归。您可能需要一个不那么暴力的算法。
  • 实际上,当网格完全解决时,可能应该有一个退出条件。 :) 否则grid[y][x] 行将撤消找到的任何解决方案。
  • @Adam 他们也在问我们是否可以发现错误。
  • 这能回答你的问题吗? How can I debug my JavaScript code?

标签: javascript recursion exit


【解决方案1】:

标准调试技术通常应该适用于此。学习使用环境的调试器。例如,如果它在您的浏览器中运行,您应该能够在浏览器的开发人员工具中设置断点,并逐行遍历代码以尝试了解发生了什么。

递归总是需要一些导致递归结束的基本条件。在您的情况下,如果没有未解决的方块,您可以通过返回 true 来表明这一点,然后将该“成功”状态传递到调用链。

此外,您对 possible 的调用已经切换了 xy 的预期参数位置。

function solve() {
  for (let y = 0; y < 9; y++) {
    for (let x = 0; x < 9; x++) {
      if (grid[y][x] === 0) {
        for (let n = 1; n < 10; n++) {
          if(possible(x,y,n)){
            grid[y][x] = n;
            var solved = solve();
            if(solved) {
                return true;
            }
            grid[y][x] = 0;
          }
        }
        return false;
      }
    }
  }
  return true; // We didn't find any unsolved squares.
}

let grid = [
  [5, 3, 0, 0, 7, 0, 0, 0, 0],
  [6, 0, 0, 1, 9, 5, 0, 0, 0],
  [0, 9, 8, 0, 0, 0, 0, 6, 0],
  [8, 0, 0, 0, 6, 0, 0, 0, 3],
  [4, 0, 0, 8, 0, 3, 0, 0, 1],
  [7, 0, 0, 0, 2, 0, 0, 0, 6],
  [0, 6, 0, 0, 0, 0, 2, 8, 0],
  [0, 0, 0, 4, 1, 9, 0, 0, 5],
  [0, 0, 0, 0, 8, 0, 0, 7, 9]];

function possible(x, y, n) {
  for (let i = 0; i < 9; i++) {
    if (grid[y][i] === n) {
      return false
    }
  }
  for (let i = 0; i < 9; i++) {
    if (grid[i][x] === n) {
      return false
    }
  }
  let x0 = Math.floor(x / 3) * 3;
  let y0 = Math.floor(y / 3) * 3;
  for (let i = 0; i < 3; i++) {
    for (let j = 0; j < 3; j++) {
      if (grid[y0 + i][x0 + j] === n) {
        return false
      }
    }
  }
  return true;
}

function solve() {
  // find the first unsolved square.
  for (let y = 0; y < 9; y++) {
for (let x = 0; x < 9; x++) {
  if (grid[y][x] === 0) {
    // try every possible number in that square
    for (let n = 1; n < 10; n++) {
      if(possible(x,y,n)){
        grid[y][x] = n;
        var solved = solve();
        // if this led to a valid board, leave the board as-is and return success.
        if(solved) {
            return true;
        }
        grid[y][x] = 0;
      }
    }
    return false;
  }
}
  }
  console.log("all squares are solved");
  return true; // We didn't find any unsolved squares.
}

console.log(solve());
console.log(grid);

【讨论】:

    【解决方案2】:

    在编写递归函数时,如果它一次又一次地重复完全相同,很有可能最终调用无限并导致堆栈溢出。

    在您的代码中,您正在调用solve 函数,该函数将从grid 的开头循环到结尾。又一次solve 函数调用了自己,导致一次又一次地循环......所以它永远不会停止,直到堆栈溢出发生。

    在下面的代码中,我确信我没有解决您的数独难题,但至少它显示了如何通过告诉在哪里重新启动循环来避免无限调用,这样它就不会再次循环。 同样,我没有解决您的数独难题.. 只是递归性质的演示。 我还添加了console.log,这样您就可以看到solve 函数每次是如何使用不同的参数调用的。

    function solve(ystart, xstart) {
      console.log('solve(', ystart + ',' + xstart, ')');
      for (let y = ystart; y < 9; y++) {
        for (let x = xstart; x < 9; x++) {
          if (grid[y][x] === 0) {
            for (let n = 1; n < 10; n++) {
              if(possible(y,x,n)){
                grid[y][x] = n;
                solve(y, x);
                grid[y][x] = 0;
              }
            }
            return;
          }
        }
      }
    }
    
    solve(0, 0);
    

    【讨论】:

    • 您提出的建议可能是对有效解决方案的优化,但它不能解决原始解决方案的任何逻辑问题。对if(grid[y][x] === 0) 的检查应该会导致下一次调用堆栈跳过被调用更改的方块,因为它已经将grid[y][x] 更改为非零值。
    【解决方案3】:

    您可以使用 Google Chrome 调试 Java 脚本

    例如,您可以在其中创建断点:

    或设置监视变量:

    使用它按F12并选择“Source”并找到您的JS文件进行调试


    如需了解更多信息,请前往阅读 https://www.w3schools.com/js/js_debugging.asp

    【讨论】:

      猜你喜欢
      • 2019-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-25
      • 2019-01-19
      • 2010-10-28
      • 2019-06-11
      相关资源
      最近更新 更多