Scala algorithm: Print a binary tree vertically
Published
Algorithm goal
Print a binary tree into a String form, such as:
1
āā“āā
2 3
| āā“āā
4 2 4
| |
6 5
āā“ā
9 7
Begin with this definition of a Binary Tree:
final case class Node[T](value: T, left: Option[Node[T]] = None, right: Option[Node[T]] = None)
Test cases in Scala
assert(
Node(1)
.withLeft(Node(2))
.withRight(Node(3))
.renderTree(_.toString)
.stringValue == " 1 \nāā“ā\n2 3"
)
assert(
Node(0)
.withLeft(Node(1).withLeft(Node(2)).withRight(Node(3)))
.renderTree(_.toString)
.stringValue == " 0 \n | \n 1 \nāā“ā\n2 3"
)
assert(Box.direct("1").stack("2").stringValue == "2\n|\n1")
assert(Box.direct("123").centre == 1)
assert(Box.direct("1234").centre == 2)
assert(
Box.direct("1").joinWith("x", Box.direct("2")).stringValue ==
" x \nāā“ā\n1 2"
)
assert(
Box.direct("1").joinWith("x", Box.direct("234")).stringValue ==
" x \nāā“āā \n1 234"
)
Algorithm in Scala
79 lines of Scala (compatible versions 2.13 & 3.0).
Explanation
The trickiest part of this algorithm is the rendering, rather than the tree traversal.
Given the tree width varies depending on how many leaf nodes there are at the very bottom, we would have to implement this algorithm with a bottom-up approach: . (this is Ā© from www.scala-algorithms.com)
- When we combine two trees, we are putting them side by side, effectively "gluing" them together
- When we create the lines joining the trees, we have some idea of a 'centre' of the left and right trees.
- When we have a parent with a single child node, we just need a direct line down.
Scala concepts & Hints
Option Type
The 'Option' type is used to describe a computation that either has a result or does not. In Scala, you can 'chain' Option processing, combine with lists and other data structures. For example, you can also turn a pattern-match into a function that return an Option, and vice-versa!
Pattern Matching
Pattern matching in Scala lets you quickly identify what you are looking for in a data, and also extract it.
Range
The
(1 to n)
syntax produces a "Range" which is a representation of a sequence of numbers.Zip
'zip' allows you to combine two lists pair-wise (meaning turn a pair of lists, into a list of pairs)
It can be used over Arrays, Lists, Views, Iterators and other collections.