Clojure 调用10上的sol计数时出现堆栈溢出(N-queens程序)
这是我第一次用clojure编程,我的程序遇到了stackoverflow的一些问题。这个程序基本上是试图找到解决N皇后问题的所有可能的方法 当我在10或更高的值上调用sol count(查找给定N的解的数量)时,我得到一个堆栈溢出Clojure 调用10上的sol计数时出现堆栈溢出(N-queens程序),clojure,stack-overflow,n-queens,Clojure,Stack Overflow,N Queens,这是我第一次用clojure编程,我的程序遇到了stackoverflow的一些问题。这个程序基本上是试图找到解决N皇后问题的所有可能的方法 当我在10或更高的值上调用sol count(查找给定N的解的数量)时,我得到一个堆栈溢出 (defn qextends? "Returns true if a queen at rank extends partial-sol." [partial-sol rank] (if (>= (count partial-sol) 1)
(defn qextends?
"Returns true if a queen at rank extends partial-sol."
[partial-sol rank]
(if (>= (count partial-sol) 1)
(and
(not= (first partial-sol) (- rank (count partial-sol)))
(not= (first partial-sol) (+ rank (count partial-sol)))
(not= (first partial-sol) rank)
(qextends? (rest partial-sol) rank))
true)
)
(defn qextend-helper [n x partial-sol partial-sol-list]
(if (<= x n)
(if (qextends? partial-sol x)
(qextend-helper n (inc x) partial-sol (conj partial-sol-list (conj partial-sol x)))
(qextend-helper n (inc x) partial-sol partial-sol-list)
)
partial-sol-list)
)
(defn qextend
"Given a vector *partial-sol-list* of all partial solutions of length k,
returns a vector of all partial solutions of length k + 1.
"
[n partial-sol-list]
(if (>= (count partial-sol-list) 1)
(vec (concat (qextend-helper n 1 (first partial-sol-list) [])
(qextend n (rest partial-sol-list))))
nil))
(defn sol-count-helper
[n x partial-sol-list]
(if (<= x (- n 1))
(sol-count-helper n (+ 1 x) (qextend n partial-sol-list))
(qextend n partial-sol-list))
)
(defn sol-count
"Returns the total number of n-queens solutions on an n x n board."
[n]
(count (sol-count-helper n 1 [[]]))
)
(定义qextends?
“如果级别为的皇后扩展了部分sol,则返回true。”
[部分信保级]
(如果(>=(计算部分溶胶)1)
(及
(非=(第一部分溶胶)(-rank(count部分溶胶)))
(非=(第一部分溶胶)(+秩(计数部分溶胶)))
(非=(第一部分sol)等级)
(qextends?(剩余部分sol)秩)
(对)
)
(defn qextend helper[n x部分sol部分sol列表]
(如果(=(计算部分sol列表)1)
(vec(concat(qextend helper n1(第一部分sol列表)[]))
(qextend n(剩余部分sol列表)))
(零)
(定义sol count helper)
[n x部分溶胶列表]
(如果(对于初学者来说,Clojure不像其他Lisp那样具有TCO。为了缓解这一问题,Clojure提供了。在Clojure和其他Lisp中,您通常没有显式的返回,相反,重点是返回值
我安装了qextend帮助程序,为您提供了一个开始。我针对我在此处替换的代码段测试了您的一些答案,它们都解析为相同的解决方案。即使在其中包含此代码段,您仍然无法超过10,但如果您继续删除所有尾部调用递归,您应该能够克服stackoverflow错误:
(defn qextend-helper [n x partial-sol partial-sol-list]
(loop [n n
x x
partail-sol partial-sol
partial-sol-list partial-sol-list]
(when (and (<= x n)
(qextends? partail-sol x))
(recur n (inc x) partail-sol (conj partial-sol-list (conj partial-sol x))))))
最后,这种缩进样式和将括号放在自己的行上并不能提高可读性
(qextend-helper n (inc x) partial-sol partial-sol-list)
)
partial-sol-list)
)
完成dizzystar的回答:
大多数递归可以是recur
red:您可以将recur
放在if
中,从而在和和或下,将宏扩展到if
窗体。例如
(defn qextend-helper [n x partial-sol partial-sol-list]
(if (<= x n)
(if (qextends? partial-sol x)
(recur n (inc x) partial-sol (conj partial-sol-list (conj partial-sol x)))
(recur n (inc x) partial-sol partial-sol-list))
partial-sol-list)
)
…无法通过recur
处理,因为它隐藏在对concat
和vec
的函数调用中
您可以通过返回a来解决此问题,从而使partial sol list
参数变懒:
- 摆脱vec
-返回序列-和
将concat
替换为lazy cat
结果函数是
(defn qextend [n partial-sol-list]
(if (seq partial-sol-list)
(lazy-cat (qextend-helper n 1 (first partial-sol-list) [])
(qextend n (rest partial-sol-list)))
nil))
您还必须避免count
ing(从而实现)延迟序列:因此使用seq
来测试部分sol列表中是否有任何内容
它起作用了
=> (sol-count 11)
2680
哇,这真的很好。但我现在遇到的一个问题是qextend需要返回一个向量,而使用lazy cat我最终得到了一系列的解决方案。是否有某种类型的lazy vec可以生成一个向量?为什么“qextend”必须返回一个向量向量向量?为什么向量序列不能?并没有lazy vector,但你们可以将解决方案序列转换为向量,例如“(vec(sol count helper 8 1[[]]))”。还有其他依赖qextends的函数需要将其转换为向量。该答案有效,但sol count返回的计数非常理想,我希望它是qextends中的向量。“完成dizzystar的答案”---谢谢。我没有指出的一点是,根据我的经验,复发通常可以减少为更干净的东西。探索Clojure需要相当长的时间,其中的挑战是始终寻找替代品。改编的“qextend助手”是错误的。“循环”是多余的:该函数是“re”的合法且惯用的目标是的,函数是重现的合法目标。重点是重现函数不应该是第一件要达到的事情。至于循环,它只是为了让他开始。我更喜欢让人来决定改进的方向。我甚至在回答中说,这不是好的Clojure。
(defn qextend [n partial-sol-list]
(if (seq partial-sol-list)
(lazy-cat (qextend-helper n 1 (first partial-sol-list) [])
(qextend n (rest partial-sol-list)))
nil))
=> (sol-count 11)
2680