clojure中的统一成本搜索

clojure中的统一成本搜索,clojure,Clojure,这个程序似乎有一个bug,如果有人能帮忙,我将不胜感激 (defn findmincostindex [frontier] (loop [i 0 n 0] (if (< i (count frontier)) (if (< (:cost (get frontier i)) (:cost (get frontier n))) (recur (inc i) i) (recur (inc i) n)) n))) (de

这个程序似乎有一个bug,如果有人能帮忙,我将不胜感激

(defn findmincostindex [frontier]
  (loop [i 0 n 0]
    (if (< i (count frontier))
      (if (< (:cost (get frontier i)) (:cost (get frontier n)))
        (recur (inc i) i)
        (recur (inc i) n))
      n)))


(defn uniformcostsearch [graph start end]
  ((fn [frontier explored]
    (if (empty? frontier)
      "Failure"
      (let [pathwithmincost (findmincostindex (into [] frontier))
      ;(let [pathwithmincost (findmincostindex frontier)
            path (:path (get frontier pathwithmincost))
            cost (:cost (get frontier pathwithmincost))
            node (peek path)
            childs (keys (graph node))]
        (if (= node end)
          path
          (recur 
            (concat (subvec frontier 0 pathwithmincost) (subvec frontier (inc pathwithmincost))
              (map (fn [c] {:path (conj path c) :cost (+ cost ((graph node) c))})
                (filter #(not (contains? explored %)) childs)))
            (conj explored node))))))
    [{:path [start] :cost 0}] #{}))



(def graph {
        "Oradea" {
            "Zerind" 71,
            "Sibiu" 151
        },
        "Zerind" {
            "Oradea" 71,
            "Arad" 75
        },
        "Arad" {
            "Zerind" 75,
            "Sibiu" 140,
            "Timisoara" 118
        },
        "Sibiu" {
            "Oradea" 151,
            "Arad" 140,
            "Fagaras" 99,
            "Rimnicu Vilcea" 80
        },
        "Fagaras" {
            "Sibiu" 99,
            "Bucharest" 211
        },
        "Rimnicu Vilcea" {
            "Sibiu" 80,
            "Pitesti" 97,
            "Craiova" 146
        },
        "Timisoara" {
            "Arad" 118,
            "Lugoj" 111
        },
        "Lugoj" {
            "Timisoara" 111,
            "Mehadia" 70
        },
        "Pitesti" {
            "Rimnicu Vilcea" 97,
            "Craiova" 138,
            "Bucharest" 101
        },
        "Mehadia" {
            "Lugoj" 70,
            "Drobeta" 75
        },
        "Drobeta" {
            "Mehadia" 75,
            "Craiova" 120
        },
        "Craiova" {
            "Drobeta" 120,
            "Rimnicu Vilcea" 146,
            "Pitesti" 138
        },
        "Bucharest" {
            "Pitesti" 101,
            "Fagaras" 211,
            "Giurgiu" 90,
            "Urziceni" 85
        },
        "Giurgiu" {
            "Bucharest" 90
        },
        "Urziceni" {
            "Bucharest" 85,
            "Vaslui" 142,
            "Hirsova" 98
        },
        "Hirsova" {
            "Urziceni" 98,
            "Eforie" 86
        },
        "Eforie" {
            "Hirsova" 86
        },
        "Vaslui" {
            "Iasi" 92,
            "Urziceni" 142
        },
        "Iasi" {
            "Neamt" 87,
            "Vaslui" 92
        },
        "Neamt" {
            "Iasi" 87
        }})

(println (uniformcostsearch graph "Neamt" "Iasi"))
(println (uniformcostsearch graph "Neamt" "Vaslui"))
(println (uniformcostsearch graph "Bucharest" "Arad"))
但它说:

clojure.lang.LazySeq不能强制转换为 clojure.lang.ipersis

当我使用

(into [] frontier)
如果我单独使用frontier,它会说

java.lang.NullPointerException


异常发生在您的
recur
中的第一个子向量
中。您使用的是
concat
的结果,这是一个惰性序列,您不能获取惰性序列的子向量。快速修复方法是将其包装在
vec

(vec (concat (subvec frontier 0 pathwithmincost) (subvec frontier (inc pathwithmincost))
              (map (fn [c] {:path (conj path c) :cost (+ cost ((graph node) c))})
                (remove explored childs))))
其他一些提示:

  • findmincostindex
    本质上是它的一个重新实现,它的通用性较低,您可以通过使用它使它更干净
  • 集合也是函数,如果它是集合的成员,则返回参数(truthy值)。您可以使用此选项对
    (筛选(不包含已探索的%)childs))
    -例如
    (删除已探索的childs)
  • 您的
    let
    可以通过使用 以下是我的尝试:

    (let [[idx {:keys [path cost]}] (apply min-key (comp :cost second) (map-indexed vector frontier))
          node (peek path)
          childs (keys (graph node))] 
    
    这里的过程是

  • (映射索引向量边界)
    边界
    分成索引和节点对
  • min key
    查找
    (:cost(second pair))
    的最小值对
  • let
    将名称
    idx
    绑定到该对的索引,将
    path
    cost
    绑定到节点的
    :path
    :cost
    (let [[idx {:keys [path cost]}] (apply min-key (comp :cost second) (map-indexed vector frontier))
          node (peek path)
          childs (keys (graph node))]