Подтвердить что ты не робот

Нагруженный с функциональным пересечением дерева по ширине в Clojure?

Скажем, у меня есть дерево, определенное в соответствии с рекомендацией в этом сообщении, хотя это вектор в моем случае, который, надеюсь, не должен иметь значения (они являются векторами в Программе Clojure):

(def tree [1 [[2 [4] [5]] [3 [6]]]])

который должен выглядеть примерно так:

      1
     / \
    2   3
   / \  |
  4   5 6

Теперь я хотел бы сделать обход ширины в дереве без каких-либо традиционных средств, таких как очередь, и вместо этого использовать исключительно стек для передачи информации. Я знаю, что это не самый простой маршрут, но я делаю это в основном как упражнение. Также на этом этапе я не планирую возвращать коллекцию (я потом узнаю об этом как упражнение), но вместо этого просто распечатаю узлы, когда я путешествую через них.

Мое текущее решение (только начинать с Clojure, быть хорошим):

(defn breadth-recur
  [queue]
  (if (empty? queue)
    (println "Done!")
    (let [collections (first (filter coll? queue))]
      (do
        ; print out nodes on the current level, they will not be wrapped'
        ; in a [] vector and thus coll? will return false
        (doseq [node queue] (if (not (coll? node)) (println node)))
        (recur (reduce conj (first collections) (rest collections)))))))

Последняя строка не работает должным образом, и я не понимаю, как ее исправить. Я точно знаю, что хочу: мне нужно очистить каждый слой векторов, а затем объединить результаты, чтобы перейти в recur.

Проблема, которую я вижу, в основном:

IllegalArgumentException Don't know how to create ISeq from: java.lang.Long 

В принципе conj не нравится добавлять вектор к длинному, и если я сменю conj для concat, то я терпит неудачу, когда один из двух элементов, конкатенирование не является вектором. И кон, и concat терпят неудачу при столкновении:

[2 [4] [5] [3 [6]]]

Мне кажется, что мне не хватает действительно основной операции здесь, которая будет работать как на векторах, так и на примитивах в обеих позициях.

Любые предложения?

Изменить 1:

На самом деле дерево должно быть (спасибо Joost!):

(def tree [1 [2 [4] [5]] [3 [6]]])

Однако мы еще не нашли ширину - первое решение.

4b9b3361

Ответ 1

Поскольку, по-видимому, до сих пор не найдено ни одного расширенного решения, вот простой алгоритм, реализованный с первого взгляда, а затем преобразованный в ленивый:

(defn bfs-eager [tree]
  (loop [ret [], queue (conj clojure.lang.PersistentQueue/EMPTY tree)]
    (if (seq queue)
      (let [[node & children] (peek queue)]
        (recur (conj ret node) (into (pop queue) children)))
      ret)))

(defn bfs-lazy [tree]
  ((fn step [queue]
     (lazy-seq
      (when (seq queue)
        (let [[node & children] (peek queue)]
          (cons node
                (step (into (pop queue) children)))))))
   (conj clojure.lang.PersistentQueue/EMPTY tree)))

Ответ 2

Данные дерева неверны. Это должно быть [1 [2 [4] [5]] [3 [6]]]

Кроме того, вы смешиваете обход дерева с печатью и создаете результат. Все становится проще, если вы концентрируетесь на выполнении жесткой части отдельно:

(def tree [1 [2 [4] [5]] [3 [6]]])

ПРИМЕЧАНИЕ. ЭТО ГЛУБИНА-ПЕРВАЯ. СМОТРЕТЬ НИЖЕ

(defn bf "return elements in tree, breath-first"
   [[el left right]] ;; a tree is a seq of one element,
                     ;; followed by left and right child trees
   (if el
     (concat [el] (bf left) (bf right))))

(bf tree)
=> (1 2 4 5 3 6)

ПРАВИЛЬНАЯ ВЕРСИЯ

(defn bf [& roots] 
   (if (seq roots) 
       (concat (map first roots) ;; values in roots
               (apply bf (mapcat rest roots))))) ;; recursively for children

(bf tree)
=> (1 2 3 4 5 6)

Ответ 3

Это может помочь, я создавал алгоритм для оценки того, является ли дерево симметричным и использует обход ширины:

(defn node-values [nodes]
    (map first nodes))

(defn node-children [nodes]
  (mapcat next nodes))

(defn depth-traversal [nodes]
    (if (not (empty? nodes))
        (cons (node-values nodes) (depth-traversal (node-children nodes)))))

(defn tree-symmetric? [tree]
    (every?
        (fn [depth] (= depth (reverse depth)))
        (depth-traversal (list tree))))

(def tree '(1 (2 (3) (4)) (2 (4) (3))))
(node-values (list tree)) ; (1)
(node-children (list tree)) ; ((2 (3) (4)) (2 (4) (3)))
(depth-traversal (list tree)) ; ((1) (2 2) (3 4 4 3))
(tree-symmetric? tree) ; true

Ответ 4

многие комбинации reduce и conj могут быть заменены одним вызовом into в приведенном выше случае с уменьшением вам может потребоваться передать начальный пустой вектор, чтобы уменьшить до Получайте союз счастливым.