Skip to content

Commit 4ed892e

Browse files
author
Ken Power
committed
scala implementation of tree traversal
1 parent a8a60fe commit 4ed892e

File tree

2 files changed

+122
-0
lines changed

2 files changed

+122
-0
lines changed
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import scala.collection.mutable._
2+
3+
object TreeTraversal {
4+
5+
class Tree(val rowCount: Int, val childrenCount: Int) {
6+
7+
private case class Node(var id: Int) {
8+
9+
var children = ListBuffer[Node]()
10+
}
11+
12+
private val root: Node = Node(1)
13+
createAllChildren(root, rowCount, childrenCount)
14+
15+
private def createAllChildren(node: Node, rowCount: Int, childrenCount: Int): Unit = {
16+
if (rowCount <= 1) return
17+
18+
0 until childrenCount foreach { i =>
19+
node.children += Node(node.id * 10 + i + 1)
20+
createAllChildren(node.children(i), rowCount - 1, childrenCount)
21+
}
22+
}
23+
24+
private def doSomethingWithNode(node: Node) = Console.println(node.id)
25+
26+
def dfsRecursive(): Unit = {
27+
def dfsRecursive(node: Node): Unit = {
28+
doSomethingWithNode(node)
29+
node.children.foreach(dfsRecursive)
30+
}
31+
32+
dfsRecursive(root)
33+
}
34+
35+
def dfsRecursivePostOrder(): Unit = {
36+
def dfsRecursivePostOrder(node: Node): Unit = {
37+
node.children.foreach(dfsRecursivePostOrder)
38+
doSomethingWithNode(node)
39+
}
40+
41+
dfsRecursivePostOrder(root)
42+
}
43+
44+
def dfsRecursiveInOrderBinary(): Unit = {
45+
def processIfChildExists(children: ListBuffer[Node], index: Int) =
46+
if (children.isDefinedAt(index))
47+
dfsRecursiveInOrderBinary(children(index))
48+
49+
def dfsRecursiveInOrderBinary(node: Node): Unit = {
50+
if (node.children.size > 2)
51+
throw new Exception("Not a binary tree!")
52+
53+
processIfChildExists(node.children, 0)
54+
doSomethingWithNode(node)
55+
processIfChildExists(node.children, 1)
56+
}
57+
58+
dfsRecursiveInOrderBinary(this.root)
59+
}
60+
61+
def dfsStack(): Unit = {
62+
val stack = new ArrayBuffer[Node]()
63+
stack += root
64+
while (stack.nonEmpty) {
65+
doSomethingWithNode(stack(0))
66+
stack ++= stack.remove(0).children
67+
}
68+
}
69+
70+
def bfsQueue(): Unit = {
71+
val queue = new Queue[Node]()
72+
queue.enqueue(root)
73+
while (queue.nonEmpty) {
74+
doSomethingWithNode(queue.head)
75+
queue ++= queue.dequeue.children
76+
}
77+
}
78+
79+
}
80+
81+
def main(args: Array[String]): Unit = {
82+
Console.println("Creating Tree")
83+
var tree = new Tree(3, 3)
84+
85+
Console.println("Using recursive DFS :")
86+
tree.dfsRecursive
87+
88+
Console.println("Using stack-based DFS :")
89+
tree.dfsStack
90+
91+
Console.println("Using queue-based BFS :")
92+
tree.bfsQueue
93+
94+
Console.println("Using post-order recursive DFS :")
95+
tree.dfsRecursivePostOrder
96+
97+
// Uncommenting the following 2 lines will result in an exception thrown because at least one Node of the Tree
98+
// has more than 2 children and therefor a DFSRecursiveInorderBinary doesn't work.
99+
Console.println("Using in-order binary recursive DFS : (fail)")
100+
tree.dfsRecursiveInOrderBinary
101+
102+
tree = new Tree(3, 2)
103+
Console.println("Using in-order binary recursive DFS : (succeed)")
104+
tree.dfsRecursiveInOrderBinary
105+
}
106+
107+
}

contents/tree_traversal/tree_traversal.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ This has not been implemented in your chosen language, so here is the Julia code
3232
[import:3-27, lang:"php"](code/php/tree_traversal.php)
3333
{% sample lang="crystal" %}
3434
[import:1-5, lang:"crystal"](code/crystal/tree-traversal.cr)
35+
{% sample lang="scala" %}
36+
[import:7-10, lang:"scala"](code/scala/tree.scala)
3537
{% endmethod %}
3638

3739
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:
@@ -66,6 +68,8 @@ Because of this, the most straightforward way to traverse the tree might be recu
6668
[import:31-35, lang:"php"](code/php/tree_traversal.php)
6769
{% sample lang="crystal" %}
6870
[import:7-10, lang:"crystal"](code/crystal/tree-traversal.cr)
71+
{% sample lang="scala" %}
72+
[import:26-33, lang:"scala"](code/scala/tree.scala)
6973
{% endmethod %}
7074

7175
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:
@@ -108,6 +112,8 @@ Now, in this case the first element searched through is still the root of the tr
108112
[import:37-41, lang:"php"](code/php/tree_traversal.php)
109113
{% sample lang="crystal" %}
110114
[import:12-15, lang:"crystal"](code/crystal/tree-traversal.cr)
115+
{% sample lang="scala" %}
116+
[import:35-42, lang:"scala"](code/scala/tree.scala)
111117
{% endmethod %}
112118

113119
<p>
@@ -145,6 +151,8 @@ In this case, the first node visited is at the bottom of the tree and moves up t
145151
[import:43-62, lang:"php"](code/php/tree_traversal.php)
146152
{% sample lang="crystal" %}
147153
[import:17-31, lang:"crystal"](code/crystal/tree-traversal.cr)
154+
{% sample lang="scala" %}
155+
[import:44-59, lang:"scala"](code/scala/tree.scala)
148156
{% endmethod %}
149157

150158
<p>
@@ -193,6 +201,8 @@ This has not been implemented in your chosen language, so here is the Julia code
193201
[import:64-73, lang:"php"](code/php/tree_traversal.php)
194202
{% sample lang="crystal" %}
195203
[import:33-41, lang:"crystal"](code/crystal/tree-traversal.cr)
204+
{% sample lang="scala" %}
205+
[import:62-70, lang:"scala"](code/scala/tree.scala)
196206
{% endmethod %}
197207

198208
All this said, there are a few details about DFS that might not be idea, 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:
@@ -232,6 +242,8 @@ And this is exactly what Breadth-First Search (BFS) does! On top of that, it can
232242
[import:65-74, lang:"php"](code/php/tree_traversal.php)
233243
{% sample lang="crystal" %}
234244
[import:43-51, lang:"crystal"](code/crystal/tree-traversal.cr)
245+
{% sample lang="scala" %}
246+
[import:71-78, lang:"scala"](code/scala/tree.scala)
235247
{% endmethod %}
236248

237249
## Example Code
@@ -273,9 +285,12 @@ The code snippets were taken from this [Scratch project](https://scratch.mit.edu
273285
[import, lang:"php"](code/php/tree_traversal.php)
274286
{% sample lang="crystal" %}
275287
[import, lang:"crystal"](code/crystal/tree-traversal.cr)
288+
{% sample lang="scala" %}
289+
[import, lang:"scala"](code/scala/tree.scala)
276290
{% endmethod %}
277291

278292

293+
279294
<script>
280295
MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
281296
</script>

0 commit comments

Comments
 (0)