CPL 2016, week 11 Clojure immutable data structures Oleg Batrashev Institute of Computer Science, Tartu, Estonia April 25, 2016
Overview Last week ◮ Clojure language core This week ◮ Immutable data structures Next weeks ◮ Clojure simple state and design ◮ Software transactional memory ◮ Agents in Clojure
Immutable data structures 27/74 - Trees ◮ (defrecord tree [value left right]) – Java class with 3 immutable fields ◮ Having (tree. 3 :leaf (tree. 33 :leaf :leaf)) ◮ want to replace 3 with 45 tree 3 leaf tree 33 leaf leaf
Immutable data structures 27/74 - Trees ◮ (defrecord tree [value left right]) – Java class with 3 immutable fields ◮ Having (tree. 3 :leaf (tree. 33 :leaf :leaf)) ◮ want to replace 3 with 45 tree 3 tree 45 leaf tree 33 leaf leaf ◮ need to create new node and point to the subtrees ◮ in general, path from root to node must be reconstructed ◮ whoever references (part of) the tree never sees any changes
Immutable data structures 28/74 - Immutable data structures ◮ “Purely functional data structures” (book) ◮ immutable – whoever has reference never sees any changes ◮ structural sharing – old instance shares data with the new one ◮ assymptotically (almost) as efficient as transient implementations ◮ O ( log 32 n ) for unsorted collections (vector,hash-map,hash-set) ◮ O ( log 2 n ) for sorted collections (sorted-map,sorted-set) ◮ in Clojure referred as persistent collections ◮ transient counterparts ◮ handy for local,temporary operations, like StringBuffer
Immutable data structures 29/74 - Benefits ◮ may be safely ◮ passed to functions ◮ used as keys in maps and entries in sets ◮ enabling concurrency ◮ sharing collections between threads is safe ◮ free versioning ◮ old versions of the instance are untouched – may store them to a sequence and use for undo
Immutable data structures 30/74 Binary Tree - Outline Immutable data structures Binary Tree Working with immutable data Binary search tree Balanced BST Other algorithms Persistent vector and map
Immutable data structures 31/74 Binary Tree - Definition ◮ A node in binary tree can be either ◮ a leaf – :leaf ◮ an internal node – with left and right subtrees (defrecord Node [value left right ]) ◮ Ex: (Node. 15 :leaf (Node. 33 :leaf :leaf)) tree 15 tree 33 leaf leaf leaf ◮ More compactly 15 33
Immutable data structures 32/74 Binary Tree - Depth-first traversal ◮ Traverse left subtree then right subtree (defn dft [node] (if (= node :leaf) (println :leaf) (do (println (. value node )) (dft (. left node )) (dft (. right node ))))) ◮ by itself not specifically useful ◮ add accumulator
Immutable data structures 33/74 Binary Tree - DFT with accumulator (defn - dft -acc -impl [node acc] (if (= node :leaf) acc (let [lAcc (dft -acc -impl (. left node) acc) cAcc (cons (. value node) lAcc) rAcc (dft -acc -impl (. right node) cAcc )] rAcc ))) (defn dft -acc [node] (reverse (dft -acc -impl node '()))) ◮ List accumulator ◮ grow from list head ◮ reverse at the end
Immutable data structures 34/74 Binary Tree - Breadth-first traversal 1. put tree root node to a queue 2. iteratively 2.1 take tree node from the queue 2.2 process node 2.3 put child nodes to the queue ◮ queue could be immutable (see below)
Immutable data structures 35/74 Working with immutable data - Outline Immutable data structures Binary Tree Working with immutable data Binary search tree Balanced BST Other algorithms Persistent vector and map
Immutable data structures 36/74 Working with immutable data - Accessing ◮ Having collection/object like (def d {:somekey 42}) access (d :somekey) (: somekey d) (. somekey d) (get d :somekey) (get -in d [: somekey ]) 1. works for lists and maps 2. works for maps and records, may return nil 3. works for records/types/objects, may throw NullPointerException 4. works for lists, maps and records 5. multilevel get , may specify list of keys for several levels
Immutable data structures 37/74 Working with immutable data - “Update” immutable state (assoc d :newkey 43 :key3 44) (conj d [: newkey 43]) (into d {: newkey 43}) (assoc -in d [: newkey 2 3] 43) ; -> {: somekey 42, :newkey {2 {3 43}}} 1. assign new values, works with lists, maps, and records 2. update elements, works with lists, maps 3. update several elements (from another collection) 4. multilevel update, works with maps and records All of them return new object, because you are working on immutable structures!
Immutable data structures 38/74 Binary search tree - Outline Immutable data structures Binary Tree Working with immutable data Binary search tree Balanced BST Other algorithms Persistent vector and map
Immutable data structures 39/74 Binary search tree - Definition ◮ binary search tree (ordered binary tree) ◮ values in ◮ left subtree are smaller ◮ right subtree are larger 15 6 33 3 8
Immutable data structures 40/74 Binary search tree - Lookup (defn lookup [node v] (if (= node :leaf) :not -found (let [nodeV (. value node )] (cond (= v nodeV) v (< v nodeV) (lookup (. left node) v) (> v nodeV) (lookup (. right node) v))))) ◮ this is set, should have key&value to act as map
Immutable data structures 41/74 Binary search tree - Insertion (defn insert -1 [node v] (if (= :leaf node) (Node. v :leaf :leaf) (let [{nv :value nl :left nr :right} node] (if (< v nv) (Node. nv (insert -1 nl v) nr) (Node. nv nl (insert -1 nr v)) )))) 15 6 33 3 8
Immutable data structures 41/74 Binary search tree - Insertion (defn insert -1 [node v] (if (= :leaf node) (Node. v :leaf :leaf) (let [{nv :value nl :left nr :right} node] (if (< v nv) (Node. nv (insert -1 nl v) nr) (Node. nv nl (insert -1 nr v)) )))) 15 6 33 3 8 7
Immutable data structures 42/74 Binary search tree - Insertion (2) ◮ Record may have many fields – we want to redefine one ◮ Record acts as a type (later) and as a dict ◮ use assoc as for dictionary ◮ record fields accessed by Keyword keys (defn insert [node v] (if (= :leaf node) (Node. v :leaf :leaf) (if (< v (. value node )) (assoc node :left (insert (. left node) v)) (assoc node :right (insert (: right node) v)))))
Immutable data structures 43/74 Binary search tree - Deletion (1) (defn remove -smallest [node] ;; Remove the smallest value from the tree and ;; return it with the node root. (when node (let [[Yp Tp] (remove -smallest (. left node ))] (if Yp [Yp (assoc node :left Tp)] [(. value node) (: right node )])))) Yp Y ? T1 T2 T1 T2 T1 Tp Yp Yp
Immutable data structures 44/74 Binary search tree - Deletion (2) 1. find v in tree 2. cut nv2 (smallest) from right subtree nr 3. put nv2 and nr2 into the place of node (defn delete [{nv :value , nl :left , nr :right :as node} v] (cond (nil? node) nil ;; recurse into left/right subtree , reconstruct new tree (< v nv) (Node. nv (delete nl v) nr) (> v nv) (Node. nv nl (delete nr v)) ;; found the nvalue , return it and cut the right subtree (= v nv) (let [[ nv2 nr2] (remove -smallest nr)] (if -not (nil? nv2) ; is right subtree non -empty? (Node. nv2 nl nr2) nl)) ))
Immutable data structures 45/74 Balanced BST - Outline Immutable data structures Binary Tree Working with immutable data Binary search tree Balanced BST Other algorithms Persistent vector and map
Immutable data structures 46/74 Balanced BST - Overview ◮ Balanced binary search tree ◮ binary search tree ◮ complexities ◮ lookup O ( log n ) ◮ insertion O ( log n ) ◮ deletion O ( log n ) ◮ iterate over elements O ( n ) ◮ Variants ◮ Red-black tree ◮ AVL tree ◮ others
Immutable data structures 47/74 Balanced BST - Red-black tree: definition 1. A node is either red or black 2. Root node is black 3. All leaves are black 4. Both children of every red node are black 5. Same number of black nodes in each path from the root to a leaf 15 6 33 3 8 Property ◮ the longest path is less than 2 times the shortest path ◮ hint: shortest must be all blacks
Immutable data structures 48/74 Balanced BST - Rotate ◮ left and right rotation if two nodes are red ◮ assume changes are made in A (B) ◮ right rotation ◮ if U and root of A (root of B) are both red ◮ change the color of the root A (root of B) to black ◮ preserves ordering right rotate V U U V C A A B B C left rotate
Immutable data structures 49/74 Balanced BST - Rotate right: code (defn - rotate -right -if -reds [{U :left C :right :as V}] (let [A (: left U) B (: right U)] (cond (or ; two cases when need to rotate (and (= (: color U) :red) (= (: color A) :red )) (and (= (: color U) :red) (= (: color B) :red ))) (assoc U :left (assoc A :color :black) :right (assoc V :left B)) :true V ; else do not rotate )))
Immutable data structures 50/74 Balanced BST - Rotate left: code (defn - rotate -left -if -reds [{A :left V :right :as U}] (let [B (: left V) C (: right V)] (cond (or ; two cases when need to rotate (and (= (: color V) :red) (= (: color B) :red )) (and (= (: color V) :red) (= (: color C) :red ))) (assoc V :left (assoc U :right B) :right (assoc C :color :black )) :true U ; else do not rotate )))
Recommend
More recommend