Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm clojure中使用宽度优先搜索的最短路径_Algorithm_Clojure_Tree_Breadth First Search - Fatal编程技术网

Algorithm clojure中使用宽度优先搜索的最短路径

Algorithm clojure中使用宽度优先搜索的最短路径,algorithm,clojure,tree,breadth-first-search,Algorithm,Clojure,Tree,Breadth First Search,我代表一棵树 A / \ B C /\ D E 就像clojure向量中的[A[B[D][E]][C]。我需要使用广度优先搜索来找到通往目标的最短路径。我的实际向量是这样的- ["33L" ["32R" ["31L" ["30R" [false]] ["11R" ["01L" ["00R" [true]]] ["00L" [false]]]] ["30L" [false]] ["22L" ["11R" ["01L" ["00R" [true]

我代表一棵树

     A
    / \
   B   C
  /\    
 D  E    
就像clojure向量中的
[A[B[D][E]][C]
。我需要使用广度优先搜索来找到通往目标的最短路径。我的实际向量是这样的-

["33L" ["32R" ["31L" ["30R" [false]] ["11R" ["01L" ["00R" [true]]] ["00L" [false]]]] ["30L" [false]] ["22L" ["11R" ["01L" ["00R" [true]]] ["00L" [false]]] ["02R" ["01L" ["00R" [true]]] ["00L" [false]]]]] ["31R" ["30L" [false]] ["11L" ["01R" ["00L" [false]]] ["00R" [true]]]] ["22R" ["11L" ["01R" ["00L" [false]]] ["00R" [true]]] ["02L" ["01R" ["00L" [false]]] ["00R" [true]]]]]
所有以true结尾的节点都是我感兴趣的节点。有多个节点以true结尾。我需要找到从第一个节点“33L”到真实节点的最短路径。例如,如果你看顶部的树,假设D为真,C为真。从A到真实节点的最短路径是A->C

我想出了如何打印所有节点,就像使用广度优先算法进行搜索一样

(defn bfs [& nodes]
    (if (seq nodes)
        (concat (map first nodes)
            (apply bfs (apply concat (map rest nodes))))))
在我的树上运行它会给我-

("33L" "32R" "31R" "22R" "31L" "30L" "22L" "30L" "11L" "11L" "02L" "30R" "11R" false "11R" "02R" false "01R" "00R" "01R" "00R" "01R" "00R" false "01L" "00L" "01L" "00L" "01L" "00L" "00L" true "00L" true "00L" true "00R" false "00R" false "00R" false false false false true true true)
这正是广度优先搜索如何浏览整个数据集。但是,我不知道如何找到并打印到真正节点的最短路径。在你们问我之前,我已经看过了其他关于堆栈溢出的广度优先算法

更新:


我看过clojure拉链,它解决了我的问题。然而,它是深度优先的,我需要一些广度优先的东西。有没有一种方法可以使用z/down、z/left、z/right函数在其周围创建宽度优先包装器?

宽度优先搜索是一种搜索。这里返回行走顺序,如果需要最短路径,则必须修改搜索算法实现以某种方式跟踪路径。这意味着您展开的每个节点都应该具有有关到它的最短路径的信息。您可以通过传递此信息手动执行此操作

此外,Clojure几乎内置了
拉链
,可以在树上行走。您可能想使用它们

(require '[clojure.zip :as z])

> (def a ["0" ["1L" [false] [false]] ["1R" [true]]])

> ;create a zipper where vector? is a branch and (vec (rest %)) are
> ;childrens
> (def ztree (z/zipper vector? (comp vec rest) nil a))
> ztree
[["0" ["1L" [false] [false]] ["1R" [true]]] nil]
> (vector? ztree) ;zipper is vector of your original vector and some aaditional info
true
> (meta ztree) ;here are the functions
{:zip/make-node nil, 
 :zip/children #<core$comp$fn__4192 clojure.core$comp$fn__4192@59bdcbda>,   
 :zip/branch? #<core$vector_QMARK_ clojure.core$vector_QMARK_@319449e4>}
> (-> ztree z/down z/down z/up z/right z/down) ;walk the tree
[[true] 
 {:l [], 
  :pnodes [["0" ["1L" [false] [false]] ["1R" [true]]] ["1R" [true]]],
  :ppath {:l [["1L" [false] [false]]], 
          :pnodes [["0" ["1L" [false] [false]] ["1R" [true]]]], 
          :ppath nil, 
          :r nil}, 
  :r nil}]
但看起来最好自己解决这个问题

p.p.S。
你可以用拉链随意走动。只要修改您的代码,使用树上的拉链,您就可以同时获得行走顺序和最短路径。

@justanotherquirier有正确的答案,但我会对BFS的实现进行稍微不同的措辞,以获得更地道的风格(例如,使用
when let
,而不是
if
nil
let
,使用nil双关而不是
empty?
)。我还将树的数据表示隐藏在接口后面,以便在必要时更容易更改:

(defn goal? [[val]]
  (true? val))

(defn leaf? [tree]
  (= 1 (count tree)))

(defn tree-val [tree]
  (first tree))

(defn children [tree]
  (rest tree))

(defn queue [& vals]
  (apply conj clojure.lang.PersistentQueue/EMPTY vals))

(defn bfs [root]
  (loop [q (queue {:tree root :path []})]
    (when-let [{:keys [tree path]} (peek q)]
      (cond
        (goal? tree) path
        (leaf? tree) (recur (pop q))
        :else
        (let [new-path (conj path (tree-val tree))
              wrap     (fn [t] {:tree t :path new-path})]
          (recur (->> (children tree)
                      (map wrap)
                      (apply conj (pop q)))))))))

我曾经考虑过使用拉链。但是,我想看看是否有可能不使用任何内置的树行走库就可以做到这一点。
(defn goal? [[val]]
  (true? val))

(defn leaf? [tree]
  (= 1 (count tree)))

(defn tree-val [tree]
  (first tree))

(defn children [tree]
  (rest tree))

(defn queue [& vals]
  (apply conj clojure.lang.PersistentQueue/EMPTY vals))

(defn bfs [root]
  (loop [q (queue {:tree root :path []})]
    (when-let [{:keys [tree path]} (peek q)]
      (cond
        (goal? tree) path
        (leaf? tree) (recur (pop q))
        :else
        (let [new-path (conj path (tree-val tree))
              wrap     (fn [t] {:tree t :path new-path})]
          (recur (->> (children tree)
                      (map wrap)
                      (apply conj (pop q)))))))))