【问题标题】:N-queens in ScalaScala中的N皇后
【发布时间】:2017-03-14 15:17:25
【问题描述】:
  def queens(n: Int): List[List[(Int, Int)]] = {
    def placeQueens(k: Int): List[List[(Int, Int)]] =
      if (k == 0)
        List(List())
      else
        for {
          queens <- placeQueens(k - 1)
          column <- 1 to n
          queen = (k, column)
          if isSafe(queen, queens)
        } yield queen :: queens
    placeQueens(n)
  }

我不明白这段代码是如何工作的,即使我在 Eclipse 中调试过也很难。你能一步一步解释这段代码吗?顺便说一句,代码可以正常工作。我也了解 n-queens 算法,但我不了解这段代码的机制。

【问题讨论】:

    标签: scala n-queens


    【解决方案1】:

    让我们分解一下。

    def queens(n: Int): List[List[(Int, Int)]] = {
      def placeQueens(k: Int): List[List[(Int, Int)]] =
        if (k == 0)
          List(List())
        else
          for {
            queens <- placeQueens(k - 1)
            column <- 1 to n
            queen = (k, column)
            if isSafe(queen, queens)
          } yield queen :: queens
      placeQueens(n)
    }
    

    我们定义了一个函数queens(n: Int),它返回 n 个皇后在 n*n 棋盘上的所有可能位置。 queens本身的功能很简单;它只是委托给一个名为 placeQueens 的内部函数。

    placeQueens 首先列出了一个基本情况:如果我们在 0*0 棋盘上操作并放置 0 个皇后,那么只有一种(非常简单的)方法可以做到这一点。现在,这个函数的核心在 for 循环中。

    for {
      queens <- placeQueens(k - 1)
      column <- 1 to n
      queen = (k, column)
      if isSafe(queen, queens)
    } yield queen :: queens
    

    其中的一部分可以像“传统”的 for 循环一样阅读,但其中一些并不那么简单。 Scala 的 for 循环基于 Haskell 的 do-loop 语法,这可能解释了您的一些困惑。阅读方式是:

    // We're starting a for-loop
    for {
      // Call placeQueens recursively. placeQueens returns a list of
      // all possible results, so iterate over them.
      queens <- placeQueens(k - 1)
      // Iterate over each column that the kth queen could go in.
      column <- 1 to n
      // Assign the queen to that position.
      queen = (k, column)
      // If the position is safe, keep going. More precisely, if the position
      // is NOT safe, stop.
      if isSafe(queen, queens)
    // Put our new queen assignment at the beginning of the recursively computed list.
    } yield queen :: queens
    

    这些循环需要一些时间来适应。手动对循环脱糖(无论如何编译器都会这样做)以了解其含义可能具有教育意义。你可以找到翻译规则on the Scala website

    【讨论】:

    • if (k == 0) List(List()) else for { queens &lt;- placeQueens(k - 1) 重点:在左边的代码部分,我在调试的时候,k迭代到4,3,2,1,0,那么if语句为真。之后k等于1,怎么可能?
    • @coder,当k==0 时,从这次迭代返回一个空的List()。回到了哪里?返回到k==1 的上一个迭代。如果您继续单步执行代码,您应该会看到当前迭代从 yieldelse 块中返回到 上一次迭代,其中 k==2,依此类推。跨度>
    • "返回到k==1 的上一个迭代"这真的很奇怪和令人困惑。有没有更清晰的例子,包括 Scala 中的 for 循环和递归。
    猜你喜欢
    • 2021-02-02
    • 1970-01-01
    • 2020-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多