2015-05-08 102 views
2

編輯2:這整個問題和探索都是基於我錯過了拉鍊的基本概念;從特定節點的角度來看,它們代表了數據結構中的角度。因此,拉鍊始終是一對當前節點,並且從該節點的角度看,樹的其餘部分是什麼樣子。我最初試圖從拉鍊生成一個全新的結構,而拉鍊本身就是我所需要的,一直以來。我會把這一切都留給子孫後代,希望別人能夠得到幫助(或者這對任何接班人都是一種警告!)。Clojure拉鍊路徑功能不完整?

原題:

我試圖讓我的頭周圍採用拉鍊操縱樹。具體問題是我需要在運行時生成任意樹中符合任意條件的兩個節點之間的路由。

我以爲我可以使用path函數通過在當前位置調用path來獲取到某個位置的路由。但是,返回的路徑似乎忽略了達到目標所需的最後一步。

例如:

(def test-zip (vector-zip [0 [1] [2 [3 [4] 5 [6 [7] [8]]]]])) 
(-> test-zip 
    down right right down 
    right down right right 
    node) 

給人5,但

(-> test-zip 
    down right right down 
    right down right right 
    path) 

[[0 [1] [2 [3 [4] 5 [6 [7] [8]]]]] [2 [3 [4] 5 [6 [7] [8]]]] [3 [4] 5 [6 [7] [8]]]] 

這是不相同的位置(這是錯過了最後三個步驟的效果,down right right)。

它看起來像路徑函數只會讓你到樹中的父位置,忽略你和實際位置之間的任何兄弟姐妹。

我錯過了path函數的要點嗎?我假設給定一棵樹和一條路徑,將路徑應用到樹會將您帶到路徑的原始位置,而不是部分路徑。

更新:我用下面的函數定義編譯結束位置,從起始位置的節點的路徑:

(defn lca-path [start-loc end-loc] 
    (let [sczip (z/root start-loc) 
     start-path (z/path start-loc) 
     start-node (z/node start-loc) 
     end-path (z/path end-loc) 
     end-node (z/node end-loc) 
     lca-path (filter (set start-path) end-path) 
     lca-node [(last lca-path)] 
     lca-to-start (conj (vec (drop (count lca-path) start-path)) start-node) 
     lca-to-end (conj (vec (drop (count lca-path) end-path)) end-node) 
     ] 

    (concat (reverse lca-to-start) lca-node lca-to-end)) 
) 

漂亮深受聊天與@馬克費舍爾的影響,謝謝!

回答

3

我認爲你是對的,它是它的父路徑,並且確認看起來at this sitepath返回「從樹根到所有當前loc的子樹」。

爲了您的結構,樹是:

A 
/| \ 
0 o B 
    |/\ 
    1 2 C __ 
     /|\ \ 
     3 o 5 o 
     | /|\ 
     4 6 o o 
      | | 
      7 8 

所以3個節點爲A,B,C是父節點是什麼導致的5母,它們是:

A: [0 [1] [2 [3 [4] 5 [6 [7] [8]]]]] 
B: [2 [3 [4] 5 [6 [7] [8]]]] 
C: [3 [4] 5 [6 [7] [8]]] 

這是你得到的結果。

編輯:我創造了這個功能在矢量兩個值之間進行搜索,並返回它們之間的path。這有幫助嗎?我不是拉鍊專家,所以這也是爲我學習。

(defn between [v s e] 
    (let [zv (zip/vector-zip v) 
     find-loc (fn [zv l] 
        (loop [loc zv] 
        (if (= l (zip/node loc)) 
         loc 
         (if (zip/end? loc) 
          nil 
          (recur (zip/next loc)))))) 
     sv (zip/vector-zip (-> (find-loc zv s) zip/up zip/node)) 
     e-in-sv (find-loc sv e) 
     path-s-e (when (some? e-in-sv) 
        (zip/path e-in-sv))] 
    path-s-e)) 

它發現的開始和結束值的父父之間的路徑,你可以使用它像:

(def sov [0 [1] [2 [3 [4] 5 [6 [7] [8]]]]]) 
(between sov 2 6) 
=> [[2 [3 [4] 5 [6 [7] [8]]]] [3 [4] 5 [6 [7] [8]]] [6 [7] [8]]] 

我走的樹找到的父起始值,然後從父項創建一個新的拉鍊,以便從起始點限制路徑。輔助函數「find-loc」爲你正在尋找的條目返回一個拉鍊,例如向量中的「5」。然後sv是包含起始值的父向量。

如果沒有路徑,則返回零,例如,在1到4之間你必須遍歷2個元素。

這是爲了迴應您的意見,必須找到最終節點中的值(例如5,[3 [4] 5 [6 [7] [8]]]),我認爲您不需要這樣做,但沒有您正在做的事情的真實例子很難評論。

順便說一句,有可能是/橫向的更好的方法比自定義函數的矢量找到值,但正如我所說的拉鍊是相當新的對我來說太。

+0

因此,一旦你到達父子樹,你必須在最後一個子樹的直接子孫後面手動搜索所需的節點?假設立即下降的節點是「3」。 '[4]','5'和'[6 [7] [8]]'在這種情況下搜索範圍並不太大。但是,對於所有四個位置都返回相同的路徑,這並不奇怪嗎?有沒有其他一些慣用的方法來捕捉路線到拉鍊我失蹤的位置? –

+0

我很高興與你分享這一次的旅程。我已經更新了我的答案,在2點之間包含一個查找器。這是否符合你想要實現的目標? –

+0

另外我認爲這是因爲你使用簡單的矢量拉鍊,而不是一些自定義的拉鍊來覆蓋你的數據。 –