From b36f761bb2deffe754e30ba330b3a8c5dc961ee9 Mon Sep 17 00:00:00 2001 From: Amaras Date: Sat, 11 Jul 2020 23:58:25 +0200 Subject: [PATCH 1/2] Added tree traversal in Coconut --- .../code/coconut/tree_traversal.coco | 89 +++++++++++++++++++ contents/tree_traversal/tree_traversal.md | 14 +++ 2 files changed, 103 insertions(+) create mode 100644 contents/tree_traversal/code/coconut/tree_traversal.coco diff --git a/contents/tree_traversal/code/coconut/tree_traversal.coco b/contents/tree_traversal/code/coconut/tree_traversal.coco new file mode 100644 index 000000000..4b915230f --- /dev/null +++ b/contents/tree_traversal/code/coconut/tree_traversal.coco @@ -0,0 +1,89 @@ +from collections import deque + +data Node(value: int, children: Node[]) + +def dfs_recursive(Node(value, children)): + """A depth first approach for printing out all values in a tree.""" + print(value, end=' ') + for child in children: + dfs_recursive(child) + +def dfs_recursive_postorder(Node(value, children)): + """A depth first approach for printing out all values in a tree starting from the bottom.""" + for child in children: + dfs_recursive_postorder(child) + print(value, end=' ') + +def dfs_recursive_inorder_btree(Node(value, children)): + """A depth first search approach for printing all values in a binary tree.""" + case len(children): + match 2: + dfs_recursive_inorder_btree(children[0]) + print(value, end=' ') + dfs_recursive_inorder_btree(children[1]) + match 1: + dfs_recursive_inorder_btree(children[0]) + print(value, end=' ') + match 0: + print(value, end=' ') + else: + print('Invalid binary tree') + +def dfs_stack(node is Node): + """A depth first approach for printing out all values in a tree using a stack.""" + stack = [node] + while stack: + current_node = stack.pop() + print(current_node.value, end=' ') + for child in current_node.children: + stack.append(child) + +def bfs_queue(node is Node): + """A breadth first search approach for printing out all values in a tree.""" + queue = deque([node]) + while queue: + current_node = queue.popleft() + print(current_node.value, end=' ') + for child in current_node.children: + queue.append(child) + +def create_tree(num_rows, num_child): + """Creates a simple tree, where every node has 'num_child' children and is 'num_rows' deep.""" + if num_rows == 1: + return Node(1, ()) + else: + return Node(num_rows, tuple(create_tree(num_rows-1, num_child) for _ in range(num_child))) + + +if __name__ =='__main__': + # A ternary tree for testing + tree = create_tree(3, 3) + + # Should print: 3 2 1 1 1 2 1 1 1 2 1 1 1 + print("Recursive DFS:") + dfs_recursive(tree) + print() + + # Should print: 1 1 1 2 1 1 1 2 1 1 1 2 3 + print("Recursive Postorder DFS:") + dfs_recursive_postorder(tree) + print() + + # Should print: 3 2 1 1 1 2 1 1 1 2 1 1 1 + print("Stack (DFS):") + dfs_stack(tree) + print() + + # Should print: 3 2 2 2 1 1 1 1 1 1 1 1 1 + print("Queue (BFS):") + bfs_queue(tree) + print() + + # And a binary tree for testing + binary_tree = create_tree(3, 2) + + # Should print: 1 2 1 3 1 2 1 + print("Recursive Inorder Binary Tree:") + dfs_recursive_inorder_btree(binary_tree) + print() + diff --git a/contents/tree_traversal/tree_traversal.md b/contents/tree_traversal/tree_traversal.md index f53af8a15..3cc5a2fbb 100644 --- a/contents/tree_traversal/tree_traversal.md +++ b/contents/tree_traversal/tree_traversal.md @@ -42,6 +42,8 @@ As a note, a `node` struct is not necessary in javascript, so this is an example [import:3-3, lang:"lisp"](code/clisp/tree-traversal.lisp) {% sample lang="m" %} [import:6-6, lang:"matlab"](code/matlab/tree.m) +{% sample lang="coco" %} +[import:3-3, lang:"coconut"](code/coconut/tree_traversal.coco) {% endmethod %} Because of this, the most straightforward way to traverse the tree might be recursive. This naturally leads us to the Depth-First Search (DFS) method: @@ -85,6 +87,8 @@ Because of this, the most straightforward way to traverse the tree might be recu [import:5-10, lang:"lisp"](code/clisp/tree-traversal.lisp) {% sample lang="m" %} [import:31-45, lang:"matlab"](code/matlab/tree.m) +{% sample lang="coco" %} +[import:5-9, lang:"coconut"](code/coconut/tree_traversal.coco) {% endmethod %} At least to me, this makes a lot of sense. We fight recursion with recursion! First, we first output the node we are on and then we call `DFS_recursive(...)` on each of its children nodes. This method of tree traversal does what its name implies: it goes to the depths of the tree first before going through the rest of the branches. In this case, the ordering looks like: @@ -137,6 +141,8 @@ Now, in this case the first element searched through is still the root of the tr [import:12-17, lang:"lisp"](code/clisp/tree-traversal.lisp) {% sample lang="m" %} [import:47-62, lang:"matlab"](code/matlab/tree.m) +{% sample lang="coco" %} +[import:11-15, lang:="coconut"](codo/coconut/tree_traversal.coco) {% endmethod %}

@@ -184,6 +190,8 @@ In this case, the first node visited is at the bottom of the tree and moves up t [import:19-32, lang:"lisp"](code/clisp/tree-traversal.lisp) {% sample lang="m" %} [import:64-82, lang:"matlab"](code/matlab/tree.m) +{% sample lang="coco" %} +[import:17-30, lang:"coconut"](code/coconut/tree_traversal.coco) {% endmethod %}

@@ -240,6 +248,8 @@ In code, it looks like this: [import:34-43, lang:"lisp"](code/clisp/tree-traversal.lisp) {% sample lang="m" %} [import:84-106, lang:"matlab"](code/matlab/tree.m) +{% sample lang="coco" %} +[import:32-39, lang:"coconut"](code/coconut/tree_traversal.coco) {% endmethod %} All this said, there are a few details about DFS that might not be ideal, depending on the situation. For example, if we use DFS on an incredibly long tree, we will spend a lot of time going further and further down a single branch without searching the rest of the data structure. In addition, it is not the natural way humans would order a tree if asked to number all the nodes from top to bottom. I would argue a more natural traversal order would look something like this: @@ -289,6 +299,8 @@ And this is exactly what Breadth-First Search (BFS) does! On top of that, it can [import:45-56, lang:"lisp"](code/clisp/tree-traversal.lisp) {% sample lang="m" %} [import:108-129, lang:"matlab"](code/matlab/tree.m) +{% sample lang="coco" %} +[import:41-48, lang:"coconut"](code/coconut/tree_traversal.coco) {% endmethod %} ## Video Explanation @@ -351,6 +363,8 @@ The code snippets were taken from this [Scratch project](https://scratch.mit.edu [import, lang:"lisp"](code/clisp/tree-traversal.lisp) {% sample lang="m" %} [import, lang:"matlab"](code/matlab/tree.m) +{% sample lang="coco" %} +[import, lang:"coconut"](code/coconut/tree_traversal.coco) {% endmethod %} From f1a06693dc76e1a3c8f0bbb7cd5addf819d68f46 Mon Sep 17 00:00:00 2001 From: Amaras Date: Sun, 12 Jul 2020 17:57:50 +0200 Subject: [PATCH 2/2] Addressed review by @berquist: formatting changes --- contents/tree_traversal/code/coconut/tree_traversal.coco | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/contents/tree_traversal/code/coconut/tree_traversal.coco b/contents/tree_traversal/code/coconut/tree_traversal.coco index 4b915230f..c7433fea2 100644 --- a/contents/tree_traversal/code/coconut/tree_traversal.coco +++ b/contents/tree_traversal/code/coconut/tree_traversal.coco @@ -48,11 +48,13 @@ def bfs_queue(node is Node): queue.append(child) def create_tree(num_rows, num_child): - """Creates a simple tree, where every node has 'num_child' children and is 'num_rows' deep.""" + """Creates a simple tree, where every node has + 'num_child' children and is 'num_rows' deep.""" if num_rows == 1: return Node(1, ()) else: - return Node(num_rows, tuple(create_tree(num_rows-1, num_child) for _ in range(num_child))) + return Node(num_rows, tuple(create_tree(num_rows-1, num_child) + for _ in range(num_child))) if __name__ =='__main__':