我需要按照以下方式使用四叉树:
p /| |\ / | | \ / | | \ p w b p /| |\ /| |\ / | | \ / | | \ b w w b w b w b
但是它们已经使用广度优先顺序序列化为字符串,因此前一个树将具有以下表示:
ppwbpbwwbwbwb
我试图将这样的字符串转换为嵌套的矢量结构:
[ [ b w w b ] w b [ w b w b] ]
但有时以下代码无法正常工作:
(defn read-quad-tree [pattern]
(loop [r []
[s & rs :as stack] []
[p & rp :as pending] (reverse pattern)]
(cond (nil? pending) (first r)
(= (count r) 4) (recur [] (conj stack (reverse r)) pending)
(= p \p) (recur (conj r s) rs rp)
:else (recur (conj r p) stack rp))))
编辑添加一个复杂的示例:
另一个(失败的)例子。下一棵树:
| +------+-------+------+ | | | | | w w | | | +---+---+---+ +---+---+---+ | | | | | | | | | w w | | w w | | | | | +-+-+-+ +-+-+-+ +-+-+-+ +-+-+-+ | | | | | | | | | | | | | | | | b b b b w w w w b b w w b w b w
将序列化为:
ppwwppwwppwwpbbbbwwwwbbwwbwbw
目标是获得以下结构:
[ [ [ b b b b ] w w [ w w w w ] ] w w [ [ b b w w ] w w [ b w b w ] ] ]
但是我的代码给出了一个不同的(错误的)结构。
答案 0 :(得分:2)
您的代码会遇到一些代表列表而不是(预期)向量的名称。
这已经从函数的返回值中看到了,这是一个列表。
查看代码的这些部分:
(loop ...
[s & rs :as stack]
...
(recur (conj r s) rs rp)
突出显示的[s & rs :as stack]
将获取堆栈向量,将第一个元素命名为 s ,其余元素命名为 list (! ) rs 。由于 rs 是一个列表,它会在某些时候传递给 stack (通过最后的recur
),然后它也是一个列表,并且不是矢量。然后,下次 r 有4个元素时,(conj stack ...
将不会附加 r ,而是添加前缀,因为这是conj
的行为适用于列表。引自docs:
;;请注意,与矢量结合在最后完成
;;联系到列表的通知在开头就完成了
当然,这会破坏预期的算法,并解释你得到的错误结果。
虽然 r 是一个向量,但(reverse r)
returns a seq会出现类似的问题。
例如,您可以通过将(into [] ...)
应用于要将列表作为向量传递的位置来修复它。我看到你需要做的两个地方:
(defn read-quad-tree [pattern]
(loop [r []
[s & rs :as stack] []
[p & rp :as pending] (reverse pattern)]
(cond (nil? pending) (first r)
(= (count r) 4) (recur [] (conj stack (into [] (reverse r))) pending)
(= p \p) (recur (conj r s) (into [] rs) rp)
:else (recur (conj r p) stack rp))))
pending 不需要修复,因为它永远不会“感染”列表类型的其他名称。
当像这样调用纠正的代码时:
(println (read-quad-tree "ppwwppwwppwwpbbbbwwwwbbwwbwbw"))
它会输出:
[[[b b b b] w w [w w w w]] w w [[b b w w] w w [b w b w]]]
在寻找问题时,我还在(有效)模式中添加了一些检查,这可能会让您感兴趣。扩展代码如下:
(defn read-quad-tree [pattern]
(loop [r []
[s & rs :as stack] []
[p & rp :as pending] (reverse pattern)]
(cond
(nil? pending)
(if (or (seq stack) (not= (count r) 1))
{:error "Too few 'p'"}
{:tree (first r)})
(= (count r) 4)
(recur [] (conj stack (into [] (reverse r))) pending)
(= p \p)
(if (empty? s)
{:error (format "'p' at %s lacks %d children" (count pending) (- 4 (count r)))}
(recur (conj r s) (into [] rs) rp))
:else
(recur (conj r p) stack rp))))
如果一切顺利,它将返回带有树键的地图,如果模式不完整,则返回错误键。