我正在编写一个Clojure函数,通过有向图上的深度优先搜索执行拓扑排序,对于某些输入,它不会终止。它使用loop-recur,但是我没有看到在重复的参数中使用任何惰性序列,这似乎是无限循环最常见的罪魁祸首。我在纸上运行程序以获取下面的示例输入,它们似乎都运行良好。
(require '[clojure.set :as set])
;graph is a hash map, keys are nodes, vals are
;collections of other nodes that node points to
(defn DFSsort [graph]
(loop [stack `(~(ffirst graph)),
visited '()]
(let [unvisited (set/difference (set (keys graph))
(set visited)),
node (peek stack),
neigh (graph node)]
(if (empty? stack)
(if (seq unvisited)
(recur (conj stack (first unvisited))
visited)
visited) ; return
(if (seq (set/difference (set neigh) (set visited)))
(if (not-any? (partial = (first neigh)) stack)
(recur (conj stack (first neigh))
visited)
"Cycle detected!") ; abort
(recur (pop stack)
(conj visited node)))))))
(DFSsort {1 [2 3], 2 [3], 3 []})
;=> (1 2 3)
(DFSsort {1 [2 3], 2 [], 3 []})
;Infinite loop
(DFSsort {1 [2 3], 2 [], 3 [2]})
;Infinite loop
答案 0 :(得分:1)
当调用recur时,你正在使用当前节点的第一个邻居,而不是第一个未访问的邻居。对于节点1,您始终将节点2添加到堆栈中。
试试这个:
(defn DFSsort [graph]
(loop [stack `(~(ffirst graph)),
visited '()]
(println stack visited)
(let [unvisited (set/difference (set (keys graph))
(set visited)),
node (peek stack),
neigh (graph node)
unseen-neigh (seq (set/difference (set neigh) (set visited)))]
(if (empty? stack)
(if (seq unvisited)
(recur (conj stack (first unvisited))
visited)
visited) ; return
(if unseen-neigh
(if (not-any? (partial = (first unseen-neigh)) stack)
(recur (conj stack (first unseen-neigh))
visited)
"Cycle detected!") ; abort
(recur (pop stack)
(conj visited node)))))))