(ns tree (:require [clojure.spec.alpha :as s])) (s/def ::value any?) (s/def ::children (s/coll-of ::tree :kind vector?)) (s/def ::tree (s/keys :req-un [::value] :opt-un [::children])) (defprotocol TreeOperations "Protocol defining fundamental tree operations" (add-child [this child-value] "Adds a new child node with the specified value") (remove-child [this index] "Removes the child at the specified index") (update-node-value [this new-value] "Updates the value of the current node") (get-child-at [this index] "Gets the child node at the specified index") (get-tree-depth [this] "Calculates the depth of the tree") (get-tree-size [this] "Calculates the total number of nodes in the tree")) (defrecord TreeNode [value children] TreeOperations (add-child [this child-value] (let [new-child (->TreeNode child-value [])] (if (s/valid? ::tree new-child) (update this :children (fnil conj []) new-child) (throw (ex-info "Invalid child node" {:value child-value :spec-error (s/explain-str ::tree new-child)}))))) (remove-child [this index] (if (and (>= index 0) (< index (count (:children this)))) (update this :children #(vec (concat (subvec % 0 index) (subvec % (inc index))))) this)) (update-node-value [this new-value] (let [updated (assoc this :value new-value)] (if (s/valid? ::tree updated) updated (throw (ex-info "Invalid node value" {:value new-value :spec-error (s/explain-str ::tree updated)}))))) (get-child-at [this index] (get-in this [:children index])) (get-tree-depth [this] (if (empty? (:children this)) 1 (inc (apply max (map get-tree-depth (:children this)))))) (get-tree-size [this] (inc (reduce + 0 (map get-tree-size (:children this)))))) (defn create-tree "Creates a new tree with the specified value" [value] (let [tree (->TreeNode value [])] (if (s/valid? ::tree tree) tree (throw (ex-info "Invalid tree structure" {:value value :spec-error (s/explain-str ::tree tree)}))))) (defn pre-order "Performs a pre-order traversal of the tree" [tree] (when (s/valid? ::tree tree) (cons (:value tree) (mapcat pre-order (:children tree))))) (defn post-order "Performs a post-order traversal of the tree" [tree] (when (s/valid? ::tree tree) (concat (mapcat post-order (:children tree)) [(:value tree)]))) (defn breadth-first "Performs a breadth-first traversal of the tree" [tree] (when (s/valid? ::tree tree) (loop [queue [tree] result []] (if (empty? queue) result (let [current (first queue)] (recur (concat (rest queue) (:children current)) (conj result (:value current)))))))) (defn find-node "Finds a node in the tree that satisfies the predicate" [tree pred] (when (s/valid? ::tree tree) (cond (pred tree) tree (empty? (:children tree)) nil :else (some #(find-node % pred) (:children tree))))) (defn map-tree "Applies function f to each node value in the tree" [f tree] (when (s/valid? ::tree tree) (->TreeNode (f (:value tree)) (mapv #(map-tree f %) (:children tree))))) (comment (def sample-tree (-> (create-tree 1) (add-child 2) (add-child 3) (add-child 4))) (def nested-tree (-> sample-tree (add-child 5) (add-child 6))) (pre-order nested-tree) ;; => (1 2 3 4 5 6) (post-order nested-tree) ;; => (2 3 4 5 6 1) (breadth-first nested-tree) ;; => [1 2 3 4 5 6] (get-tree-depth nested-tree) ;; => 2 (get-tree-size nested-tree) ;; => 6 (map-tree #(* 2 %) nested-tree) ;; => TreeNode with doubled values (find-node nested-tree #(= 3 (:value %))) ;; => TreeNode{:value 3, :children []} )
![Cover image for Clojure Is Awesome!!! [PART 7]](https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t7eo4be5gv4k2r320vky.jpg)
For further actions, you may consider blocking this person and/or reporting abuse
Top comments (0)