This repository has been archived by the owner on May 30, 2023. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
63dca45
commit abba7c6
Showing
7 changed files
with
342 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# Instructions | ||
|
||
Creating a zipper for a binary tree. | ||
|
||
[Zippers][zipper] are a purely functional way of navigating within a data structure and manipulating it. | ||
They essentially contain a data structure and a pointer into that data structure (called the focus). | ||
|
||
For example given a rose tree (where each node contains a value and a list of child nodes) a zipper might support these operations: | ||
|
||
- `from_tree` (get a zipper out of a rose tree, the focus is on the root node) | ||
- `to_tree` (get the rose tree out of the zipper) | ||
- `value` (get the value of the focus node) | ||
- `prev` (move the focus to the previous child of the same parent, | ||
returns a new zipper) | ||
- `next` (move the focus to the next child of the same parent, returns a | ||
new zipper) | ||
- `up` (move the focus to the parent, returns a new zipper) | ||
- `set_value` (set the value of the focus node, returns a new zipper) | ||
- `insert_before` (insert a new subtree before the focus node, it | ||
becomes the `prev` of the focus node, returns a new zipper) | ||
- `insert_after` (insert a new subtree after the focus node, it becomes | ||
the `next` of the focus node, returns a new zipper) | ||
- `delete` (removes the focus node and all subtrees, focus moves to the | ||
`next` node if possible otherwise to the `prev` node if possible, | ||
otherwise to the parent node, returns a new zipper) | ||
|
||
[zipper]: https://en.wikipedia.org/wiki/Zipper_%28data_structure%29 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{ | ||
"authors": [ | ||
"ErikSchierboom" | ||
], | ||
"files": { | ||
"solution": [ | ||
"src/zipper.cljs" | ||
], | ||
"test": [ | ||
"test/zipper_test.cljs" | ||
], | ||
"example": [ | ||
".meta/src/example.cljs" | ||
] | ||
}, | ||
"blurb": "Creating a zipper for a binary tree." | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
(ns zipper) | ||
|
||
(defn from-trail [tree last] | ||
(if (= (nth last 0) "left") | ||
{:value (nth last 1), :left tree, :right (nth last 2)} | ||
{:value (nth last 1), :left (nth last 2), :right tree})) | ||
|
||
(defn from-tree [tree] | ||
{:tree tree :trail []}) | ||
|
||
(defn value [z] | ||
(:value (:tree z))) | ||
|
||
(defn zipper [tree trail] | ||
{:tree tree :trail trail}) | ||
|
||
(defn left [z] | ||
(when (:left (:tree z)) | ||
(zipper (:left (:tree z)) | ||
(conj [["left" (:value (:tree z)) (:right (:tree z))]] | ||
(:trail z))))) | ||
(defn right [z] | ||
(when (:right (:tree z)) | ||
(zipper (:right (:tree z)) | ||
(conj [["right" (:value (:tree z)) (:left (:tree z))]] | ||
(:trail z))))) | ||
|
||
(defn rebuild-tree [tree trail] | ||
(if (= 0 (count trail)) | ||
tree | ||
(recur (from-trail tree (first trail)) (fnext trail)))) | ||
|
||
(defn to-tree [z] | ||
(rebuild-tree (:tree z) (:trail z))) | ||
|
||
(defn up [z] | ||
(when-not (zero? (count (:trail z))) | ||
(zipper (from-trail (:tree z) (first (:trail z))) | ||
(fnext (:trail z))))) | ||
|
||
(defn set-value [z value] | ||
(zipper {:value value, | ||
:left (:left (:tree z)), | ||
:right (:right (:tree z))} | ||
(:trail z))) | ||
|
||
(defn set-left [z left] | ||
(zipper {:value (:value (:tree z)), | ||
:left left, | ||
:right (:right (:tree z))} | ||
(:trail z))) | ||
|
||
(defn set-right [z right] | ||
(zipper {:value (:value (:tree z)), | ||
:left (:left (:tree z)), | ||
:right right} | ||
(:trail z))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{:deps | ||
{org.clojure/clojure {:mvn/version "1.10.1"} | ||
org.clojure/clojurescript {:mvn/version "1.10.773"}} | ||
|
||
:aliases | ||
{:test | ||
{:extra-paths ["test"] | ||
:extra-deps | ||
{olical/cljs-test-runner {:mvn/version "3.8.0"}} | ||
:main-opts ["-m" "cljs-test-runner.main"]}}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
(ns zipper) | ||
|
||
(defn from-tree [] | ||
) | ||
|
||
(defn value [] | ||
) | ||
|
||
(defn left [] | ||
) | ||
|
||
(defn right [] | ||
) | ||
|
||
(defn to-tree [] | ||
) | ||
|
||
(defn up [] | ||
) | ||
|
||
(defn set-value [] | ||
) | ||
|
||
(defn set-left [] | ||
) | ||
|
||
(defn set-right [] | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
(ns zipper-test | ||
(:require [clojure.test :refer [deftest testing is run-tests]] | ||
zipper)) | ||
|
||
(def t1 {:value 1, :left {:value 2, :left nil, :right {:value 3, :left nil, :right nil}}, :right {:value 4, :left nil, :right nil}}) | ||
|
||
(deftest expected-value-test | ||
(let [tree {:value 1 | ||
:left {:value 2 | ||
:left nil | ||
:right {:value 3 | ||
:left nil | ||
:right nil}} | ||
:right {:value 4 | ||
:left nil | ||
:right nil}}] | ||
(testing "data is retained" | ||
(is (= tree (-> tree zipper/from-tree zipper/to-tree)))) | ||
(testing "left, right and value" | ||
(is (= 3 (-> t1 | ||
zipper/from-tree | ||
zipper/left | ||
zipper/right | ||
zipper/value | ||
)))) | ||
(testing "dead end" | ||
(is (nil? (-> tree | ||
zipper/from-tree | ||
zipper/left | ||
zipper/left)))) | ||
(testing "tree from deep focus" | ||
(is (= tree (-> tree | ||
zipper/from-tree | ||
zipper/left | ||
zipper/right | ||
zipper/to-tree)))) | ||
(testing "traversing up from top" | ||
(is (= nil | ||
(-> tree | ||
zipper/from-tree | ||
zipper/up)))) | ||
(testing "left, right, and up" | ||
(is (= 3 | ||
(-> tree | ||
zipper/from-tree | ||
zipper/left | ||
zipper/up | ||
zipper/right | ||
zipper/up | ||
zipper/left | ||
zipper/right | ||
zipper/value)))) | ||
(testing "test ability to descend multiple levels and return" | ||
(is (= 1 | ||
(-> tree | ||
zipper/from-tree | ||
zipper/left | ||
zipper/right | ||
zipper/up | ||
zipper/up | ||
zipper/value)))) | ||
(testing "set_value" | ||
(is (= {:value 1 | ||
:left {:value 5 | ||
:left nil | ||
:right {:value 3 | ||
:left nil | ||
:right nil}} | ||
:right {:value 4 | ||
:left nil | ||
:right nil}} | ||
(-> tree | ||
zipper/from-tree | ||
zipper/left | ||
(zipper/set-value 5) | ||
zipper/to-tree)))) | ||
(testing "set_value after traversing up" | ||
(is (= {:value 1 | ||
:left {:value 5 | ||
:left nil | ||
:right {:value 3 | ||
:left nil | ||
:right nil}} | ||
:right {:value 4 | ||
:left nil | ||
:right nil}} | ||
(-> tree | ||
zipper/from-tree | ||
zipper/left | ||
zipper/right | ||
zipper/up | ||
(zipper/set-value 5) | ||
zipper/to-tree)))) | ||
(testing "set_left with leaf" | ||
(is (= {:value 1 | ||
:left {:value 2 | ||
:left {:value 5 | ||
:left nil | ||
:right nil} | ||
:right {:value 3 | ||
:left nil | ||
:right nil}} | ||
:right {:value 4 | ||
:left nil | ||
:right nil}} | ||
(-> tree | ||
zipper/from-tree | ||
zipper/left | ||
(zipper/set-left {:value 5 | ||
:left nil | ||
:right nil}) | ||
zipper/to-tree)))) | ||
(testing "set_right with null" | ||
(is (= {:value 1 | ||
:left {:value 2 | ||
:left nil | ||
:right nil} | ||
:right {:value 4 | ||
:left nil | ||
:right nil}} | ||
(-> tree | ||
zipper/from-tree | ||
zipper/left | ||
(zipper/set-right nil) | ||
zipper/to-tree)))) | ||
(testing "set_right with subtree" | ||
(is (= {:value 1 | ||
:left {:value 2 | ||
:left nil | ||
:right {:value 3 | ||
:left nil | ||
:right nil}} | ||
:right {:value 6 | ||
:left {:value 7 | ||
:left nil | ||
:right nil} | ||
:right {:value 8 | ||
:left nil | ||
:right nil}}} | ||
(-> tree | ||
zipper/from-tree | ||
(zipper/set-right {:value 6 | ||
:left {:value 7 | ||
:left nil | ||
:right nil} | ||
:right {:value 8 | ||
:left nil | ||
:right nil}}) | ||
zipper/to-tree)))) | ||
(testing "set_value on deep focus" | ||
(is (= {:value 1 | ||
:left {:value 2 | ||
:left nil | ||
:right {:value 5 | ||
:left nil | ||
:right nil}} | ||
:right {:value 4 | ||
:left nil | ||
:right nil}} | ||
(-> tree | ||
zipper/from-tree | ||
zipper/left | ||
zipper/right | ||
(zipper/set-value 5) | ||
zipper/to-tree)))))) | ||
|
||
(deftest sameResultFromOperations-test | ||
(testing "different paths to same zipper" | ||
(is (= (-> {:value 1 | ||
:left {:value 2 | ||
:left nil | ||
:right {:value 3 | ||
:left nil | ||
:right nil}} | ||
:right {:value 4 | ||
:left nil | ||
:right nil}} | ||
zipper/from-tree | ||
zipper/right) | ||
(-> {:value 1 | ||
:left {:value 2 | ||
:left nil | ||
:right {:value 3 | ||
:left nil | ||
:right nil}} | ||
:right {:value 4 | ||
:left nil | ||
:right nil}} | ||
zipper/from-tree | ||
zipper/left | ||
zipper/up | ||
zipper/right))))) |