\(\newcommand{\Java}{\href{http://java.com/en/}{Java}}\) \(\newcommand{\Python}{\href{https://www.python.org/}{Python}}\) \(\newcommand{\CPP}{\href{http://www.cplusplus.com/}{C++}}\) \(\newcommand{\ST}[1]{{\Blue{\textsf{#1}}}}\) \(\newcommand{\PseudoCode}[1]{{\color{blue}\textsf{#1}}}\) \(%\newcommand{\subheading}[1]{\textbf{\large\color{aaltodgreen}#1}}\) \(\newcommand{\subheading}[1]{\large{\usebeamercolor[fg]{frametitle} #1}}\) \(\newcommand{\Blue}[1]{{\color{flagblue}#1}}\) \(\newcommand{\Red}[1]{{\color{aaltored}#1}}\) \(\newcommand{\Emph}[1]{\emph{\color{flagblue}#1}}\) \(\newcommand{\Engl}[1]{({\em engl.}\ #1)}\) \(\newcommand{\Pointer}{\raisebox{-1ex}{\huge\ding{43}}\ }\) \(\newcommand{\Set}[1]{\{#1\}}\) \(\newcommand{\Setdef}[2]{\{{#1}\mid{#2}\}}\) \(\newcommand{\PSet}[1]{\mathcal{P}(#1)}\) \(\newcommand{\Card}[1]{{\vert{#1}\vert}}\) \(\newcommand{\Tuple}[1]{(#1)}\) \(\newcommand{\Implies}{\Rightarrow}\) \(\newcommand{\Reals}{\mathbb{R}}\) \(\newcommand{\Seq}[1]{(#1)}\) \(\newcommand{\Arr}[1]{[#1]}\) \(\newcommand{\Floor}[1]{{\lfloor{#1}\rfloor}}\) \(\newcommand{\Ceil}[1]{{\lceil{#1}\rceil}}\) \(\newcommand{\Path}[1]{(#1)}\) \(%\newcommand{\Lg}{\lg}\) \(\newcommand{\Lg}{\log_2}\) \(\newcommand{\BigOh}{O}\) \(\newcommand{\Oh}[1]{\BigOh(#1)}\) \(\newcommand{\todo}[1]{\Red{\textbf{TO DO: #1}}}\) \(\newcommand{\NULL}{\textsf{null}}\) \(\newcommand{\Insert}{\ensuremath{\textsc{insert}}}\) \(\newcommand{\Search}{\ensuremath{\textsc{search}}}\) \(\newcommand{\Delete}{\ensuremath{\textsc{delete}}}\) \(\newcommand{\Remove}{\ensuremath{\textsc{remove}}}\) \(\newcommand{\Parent}[1]{\mathop{parent}(#1)}\) \(\newcommand{\ALengthOf}[1]{{#1}.\textit{length}}\) \(\newcommand{\TRootOf}[1]{{#1}.\textit{root}}\) \(\newcommand{\TLChildOf}[1]{{#1}.\textit{leftChild}}\) \(\newcommand{\TRChildOf}[1]{{#1}.\textit{rightChild}}\) \(\newcommand{\TNode}{x}\) \(\newcommand{\TNodeI}{y}\) \(\newcommand{\TKeyOf}[1]{{#1}.\textit{key}}\) \(\newcommand{\PEnqueue}[2]{{#1}.\textsf{enqueue}(#2)}\) \(\newcommand{\PDequeue}[1]{{#1}.\textsf{dequeue}()}\) \(\newcommand{\Def}{\mathrel{:=}}\) \(\newcommand{\Eq}{\mathrel{=}}\) \(\newcommand{\Asgn}{\mathrel{\leftarrow}}\) \(%\newcommand{\Asgn}{\mathrel{:=}}\) \(%\) \(% Heaps\) \(%\) \(\newcommand{\Downheap}{\textsc{downheap}}\) \(\newcommand{\Upheap}{\textsc{upheap}}\) \(\newcommand{\Makeheap}{\textsc{makeheap}}\) \(%\) \(% Dynamic sets\) \(%\) \(\newcommand{\SInsert}[1]{\textsc{insert}(#1)}\) \(\newcommand{\SSearch}[1]{\textsc{search}(#1)}\) \(\newcommand{\SDelete}[1]{\textsc{delete}(#1)}\) \(\newcommand{\SMin}{\textsc{min}()}\) \(\newcommand{\SMax}{\textsc{max}()}\) \(\newcommand{\SPredecessor}[1]{\textsc{predecessor}(#1)}\) \(\newcommand{\SSuccessor}[1]{\textsc{successor}(#1)}\) \(%\) \(% Union-find\) \(%\) \(\newcommand{\UFMS}[1]{\textsc{make-set}(#1)}\) \(\newcommand{\UFFS}[1]{\textsc{find-set}(#1)}\) \(\newcommand{\UFCompress}[1]{\textsc{find-and-compress}(#1)}\) \(\newcommand{\UFUnion}[2]{\textsc{union}(#1,#2)}\) \(%\) \(% Graphs\) \(%\) \(\newcommand{\Verts}{V}\) \(\newcommand{\Vtx}{v}\) \(\newcommand{\VtxA}{v_1}\) \(\newcommand{\VtxB}{v_2}\) \(\newcommand{\VertsA}{V_\textup{A}}\) \(\newcommand{\VertsB}{V_\textup{B}}\) \(\newcommand{\Edges}{E}\) \(\newcommand{\Edge}{e}\) \(\newcommand{\NofV}{\Card{V}}\) \(\newcommand{\NofE}{\Card{E}}\) \(\newcommand{\Graph}{G}\) \(\newcommand{\SCC}{C}\) \(\newcommand{\GraphSCC}{G^\text{SCC}}\) \(\newcommand{\VertsSCC}{V^\text{SCC}}\) \(\newcommand{\EdgesSCC}{E^\text{SCC}}\) \(\newcommand{\GraphT}{G^\text{T}}\) \(%\newcommand{\VertsT}{V^\textup{T}}\) \(\newcommand{\EdgesT}{E^\text{T}}\) \(%\) \(% NP-completeness etc\) \(%\) \(\newcommand{\Poly}{\textbf{P}}\) \(\newcommand{\NP}{\textbf{NP}}\) \(\newcommand{\PSPACE}{\textbf{PSPACE}}\) \(\newcommand{\EXPTIME}{\textbf{EXPTIME}}\)

Traversing trees

In many situations it is required to traverse all the nodes in a rooted tree. This can be done in many ways, depending in which order the nodes are visited:

  • preorder traversal first visits the current node and then (recursively) its children one-by-one.

  • inorder traversal, especially on binary trees, first (recursively) visits the left child, then the node itself and then (recursively) the right child.

  • postorder traversal first visits (recursively) all the children one-by-one and then the node itself.

  • level order traversal, which is not so common, visits the nodes level-by-level left-to-right starting from the root node.

In pseudo-code, we can express each of the traversal methods as follows. Observe the use of queues in the level order traversal.

traverse-preorder(tree \(T\)): def traverse(\(n\)): visit(\(n\)) for each child \(c\) of \(n\): traverse(\(c\)) traverse(\(\TRootOf{T}\))
traverse-inorder(tree \(T\)): def traverse(\(n\)): traverse(\(\TLChildOf{n}\)) visit(\(n\)) traverse(\(\TRChildOf{n}\)) traverse(\(\TRootOf{T}\))
traverse-postorder(tree \(T\)): def traverse(\(n\)): for each child \(c\) of \(n\): traverse(\(c\)) visit(\(n\)) traverse(\(\TRootOf{T}\))
traverse-levelorder(tree \(T\)): \(level \Asgn \)new Queue \(\PEnqueue{level}{\TRootOf{T}}\) while \(level\) is non-empty: \(nextLevel \Asgn \)new Queue while \(level\) is non-empty: \(n \Asgn \PDequeue{level}\) visit(\(n\)) for each child \(c\) of \(n\): \(\PEnqueue{nextLevel}{c}\) \(level \Asgn nextLevel\)

Example

Consider the tree shown below.

_images/trees-binary-6.png

The visiting orders for the nodes in the tree are as follows.

  • ​ Preorder: \(c,d,e,g,f,a,b,h\)

  • ​ Inorder: \(g,e,f,d,c,b,a,h\)

  • ​ Postorder: \(g,f,e,d,b,h,a,c\)

  • ​ Level order: \(c,d,a,e,b,h,g,f\)

In practise, tree traversal functions may mix orders.

Example

The following Scala code shows how to print arithmetic expressions in the prefix, infix, and postfix notations.

abstract class Expr:
  def prefixStr: String
  def infixStr: String
  def postfixStr: String

case class Var(name: String) extends Expr:
  def prefixStr = "Var(\""+name+"\")"
  def infixStr = name
  def postfixStr = name

case class Negate(expr: Expr) extends Expr:
  def prefixStr = "Negate("+expr.prefixStr+")"
  def infixStr = "-" + expr.infixStr
  def postfixStr = expr.postfixStr + " -"

case class Add(left: Expr, right: Expr) extends Expr:
  def prefixStr = "Add("+left.prefixStr+","+right.prefixStr+")"
  def infixStr = "("+left.infixStr+"+"+right.infixStr+")"
  def postfixStr = left.postfixStr+" "+right.postfixStr+" +"

case class Multiply(left: Expr, right: Expr) extends Expr:
  def prefixStr = "Multiply("+left.prefixStr+","+right.prefixStr+")"
  def infixStr = "("+left.infixStr+"*"+right.infixStr+")"
  def postfixStr = left.postfixStr + " "+ right.postfixStr + " *"

case class Num(value: Double) extends Expr:
  def prefixStr = "Num("+value.toString+")"
  def infixStr = value.toString
  def postfixStr = value.toString

val e = Negate(Add(Multiply(Num(2.0),Var("x")),Var("y")))

@main def test() =
  println(e.prefixStr)
  println(e.infixStr)
  println(e.postfixStr)

The parse tree corresponding to the expression \(-(2.0x + y)\) obtained with val e = Negate(Add(Multiply(Num(2.0),Var("x")),Var("y"))) is shown below.

_images/exprs-objects.jpg
  • e.prefixStr produces Negate(Add(Multiply(Num(2.0),Var("x")),Var("y"))).

  • e.infixStr produces -((2.0*x)+y).

  • e.postfixStr gives 2.0 x * y + -.

    The postfix notation does not need parentheses and it is easy to read and evaluate from the textual representation by using a stack (see e.g. this article).