在clojure中计算两个不同子树中的节点

时间:2016-02-01 17:23:14

标签: clojure tree-traversal subtree

对Clojure来说很新,我还不知道如何做到这一点,我需要遍历一个预制的二叉搜索树,并计算2个差异子树中的节点数,如此问题

this fiddle

感谢您提供任何帮助,只需要推动即可开始

(defn familytree [tree i x]
  (cond
    (= (first(tree) i) )
      (count (zip/children))

    (= (first(tree) x))
      (count (zip/children))

    :else
      (familytree (rest tree)x i)
      ))

输入数据 (def test1 '[ 1 [ 2 [ 4 [8 9 ] 5 [ 10 11 ]] 3 [ 6 [ 12 13 ] 7 [ 14 15 ]]]])

1 个答案:

答案 0 :(得分:2)

卡梅伦

首先确定您将存储信息的Clojure持久数据类型。一旦确定:

  • 看一下Clojure zippers
  • 看看Clojure walk
  • 正如你所知的递归,取决于树的大小,你可以选择放弃像拉链这样的东西直接递归。在这种情况下,forloopreduce可能适用。

<强>更新

以下是我对要求的理解:

  1. 输入树将采用矢量/嵌套矢量结构
  2. 树中的每个向量都有一个“节点标识符”(在您的情况下是一个数字)
  3. 当节点符合某些条件
  4. 时,需要一个为节点计算子节点的函数
  5. 应该能够指定将返回计数的多个节点
  6. 鉴于此,我决定使用zipper,因为它合理地证明了逻辑的分解以达到需求目标。我还抽象了各个方面,因此计算儿童的谓词可能会发生变化。

    您需要阅读clojure.zip(网上有大量关于此的信息。

    计数器 现在覆盖了核心遍历(zippers),让我们从计数功能开始。根据要求:无论我如何到达节点,我都想计算节点的子节点:

    (defn count-children-at-node
      "Takes a zipper location and counts
      elements of it's chidren vector. Uses flatten on the
      children to sequence all the elements for counting.
      Returns a tuple identifiying the node and it's children count"
      [loc]
      (let [cnodes (zip/right loc)]
        [:node (zip/node loc)
         :count (if (nil? cnodes) ; test for no children
                  0
                  (count (flatten (zip/node cnodes))))]))
    

    The Workhorse 这是遍历发生的地方。它将是详尽的,以便找到所有可能感兴趣的节点。计数也将包括在内(见下面的结果)。我还想积累我的结果并具有灵活的谓词函数来测试结果中的包含:

    (defn find-nodes-to-count
      "Accumulate results of performing a reduction function on a node in
      the tree that matches the predicate criteria"
      [acc predfn redfn loc]
      (if (zip/end? loc)
        acc
        (if (predfn (zip/node loc))
          (recur (conj acc (redfn loc)) predfn redfn (zip/next loc))
          (recur  acc predfn redfn (zip/next loc)))))
    

    包装器 使用我的核心计数器和遍历机制,使用简单的包装功能来运用核心:

    (defn nodes-counter
      "Takes a tree collection and variable number of node identifiers
      and return an accumulation of tuples, each identifying the node and it's children
      count"
      [coll & nodevals]
      (find-nodes-to-count
        []                                  ; accumultator
        #(contains? (into #{} nodevals) %)  ; predicate function
        count-children-at-node              ; reduction function
        (zip/vector-zip coll)))             ; the tree collection
    

    <强>测试/验证 使用节点标识符变体调用nodes-counter的一些REPL示例:

    (def mytree [1 [2 [4 [8 9] 5 [ 10 11 ]] 3 [ 6 [ 12 13 ] 7 [ 14 15 ]]]])
    
    (nodes-counter mytree 16)  ; => []
    (nodes-counter mytree 15)  ; => [[:node 15 :count 0]]
    (nodes-counter mytree 2 4) ; => [[:node 2 :count 6] [:node 4 :count 2]]
    (nodes-counter mytree 4 2) ; => [[:node 2 :count 6] [:node 4 :count 2]]