Skip to content

Commit 90c9153

Browse files
committed
Tree Traversal in Ruby
1 parent afcaf4d commit 90c9153

File tree

3 files changed

+69
-0
lines changed

3 files changed

+69
-0
lines changed

CONTRIBUTORS.md

+1
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,4 @@ This file lists everyone, who contributed to this repo and wanted to show up her
4848
- dovisutu
4949
- Antetokounpo
5050
- Akash Dhiman
51+
- Tarun Vellishetty
+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
def create_tree(rows, children)
2+
return { id: rows, children: [] } if rows.zero?
3+
4+
{
5+
id: rows,
6+
children: Array.new(3, create_tree(rows - 1, children))
7+
}
8+
end
9+
10+
def dfs_preorder(tree)
11+
puts tree[:id]
12+
tree[:children].each { |child| dfs_preorder(child) }
13+
end
14+
15+
def dfs_postorder(tree)
16+
tree[:children].each { |child| dfs_postorder(child) }
17+
puts tree[:id]
18+
end
19+
20+
def dfs_inorder(tree)
21+
return unless tree
22+
23+
if tree[:children].count > 2
24+
raise 'Postorder traversal is only valid for binary trees'
25+
end
26+
27+
dfs_inorder(tree.children[0])
28+
puts tree[:id]
29+
dfs_inorder(tree.children[1])
30+
end
31+
32+
def dfs_iterative(tree)
33+
stack = [tree]
34+
while stack.count.positive?
35+
current = stack.pop
36+
puts current[:id]
37+
stack.push(*current[:children])
38+
end
39+
end
40+
41+
def bfs(tree)
42+
queue = [tree]
43+
while queue.count.positive?
44+
current = queue.shift
45+
puts current[:id]
46+
queue.push(*current[:children])
47+
end
48+
end
49+
50+
root = create_tree(3, 3)
51+
dfs_preorder(root)
52+
dfs_postorder(root)
53+
dfs_iterative(root)
54+
bfs(root)

contents/tree_traversal/tree_traversal.md

+14
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ As a note, a `node` struct is not necessary in javascript, so this is an example
3838
[import:24-27, lang:"asm-x64"](code/asm-x64/tree_traversal.s)
3939
{% sample lang="emojic" %}
4040
[import:1-3, lang:"emojicode"](code/emojicode/tree_traversal.emojic)
41+
{% sample lang="ruby" %}
42+
[import:1-8, lang:"ruby"](code/ruby/tree.rb)
4143
{% endmethod %}
4244

4345
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:
@@ -78,6 +80,8 @@ Because of this, the most straightforward way to traverse the tree might be recu
7880
[import:290-314, lang:"asm-x64"](code/asm-x64/tree_traversal.s)
7981
{% sample lang="emojic" %}
8082
[import:27-34, lang:"emojicode"](code/emojicode/tree_traversal.emojic)
83+
{% sample lang="ruby" %}
84+
[import:10-13, lang:"ruby"](code/ruby/tree.rb)
8185
{% endmethod %}
8286

8387
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:
@@ -126,6 +130,8 @@ Now, in this case the first element searched through is still the root of the tr
126130
[import:316-344, lang:"asm-x64"](code/asm-x64/tree_traversal.s)
127131
{% sample lang="emojic" %}
128132
[import:36-43, lang:"emojicode"](code/emojicode/tree_traversal.emojic)
133+
{% sample lang="ruby" %}
134+
[import:15-18, lang:"ruby"](code/ruby/tree.rb)
129135
{% endmethod %}
130136

131137
<p>
@@ -169,6 +175,8 @@ In this case, the first node visited is at the bottom of the tree and moves up t
169175
[import:346-396, lang:"asm-x64"](code/asm-x64/tree_traversal.s)
170176
{% sample lang="emojic" %}
171177
[import:45-62, lang:"emojicode"](code/emojicode/tree_traversal.emojic)
178+
{% sample lang="ruby" %}
179+
[import:20-30, lang:"ruby"](code/ruby/tree.rb)
172180
{% endmethod %}
173181

174182
<p>
@@ -222,6 +230,8 @@ In code, it looks like this:
222230
[import:398-445, lang:"asm-x64"](code/asm-x64/tree_traversal.s)
223231
{% sample lang="emojic" %}
224232
[import:64-79, lang:"emojicode"](code/emojicode/tree_traversal.emojic)
233+
{% sample lang="ruby" %}
234+
[import:32-39, lang:"ruby"](code/ruby/tree.rb)
225235
{% endmethod %}
226236

227237
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:
@@ -267,6 +277,8 @@ And this is exactly what Breadth-First Search (BFS) does! On top of that, it can
267277
[import:447-498, lang:"asm-x64"](code/asm-x64/tree_traversal.s)
268278
{% sample lang="emojic" %}
269279
[import:81-96, lang:"emojicode"](code/emojicode/tree_traversal.emojic)
280+
{% sample lang="ruby" %}
281+
[import:41-48, lang:"ruby"](code/ruby/tree.rb)
270282
{% endmethod %}
271283

272284
## Video Explanation
@@ -322,6 +334,8 @@ The code snippets were taken from this [Scratch project](https://scratch.mit.edu
322334
[import, lang:"asm-x64"](code/asm-x64/tree_traversal.s)
323335
{% sample lang="emojic" %}
324336
[import, lang:"emojicode"](code/emojicode/tree_traversal.emojic)
337+
{% sample lang="ruby" %}
338+
[import, lang:"ruby"](code/ruby/tree.rb)
325339
{% endmethod %}
326340

327341

0 commit comments

Comments
 (0)