\(\) \(%\newcommand{\CLRS}{\href{https://mitpress.mit.edu/books/introduction-algorithms}{Cormen et al}}\) \(\newcommand{\CLRS}{\href{https://mitpress.mit.edu/books/introduction-algorithms}{Introduction to Algorithms, 3rd ed.} (\href{http://libproxy.aalto.fi/login?url=http://site.ebrary.com/lib/aalto/Doc?id=10397652}{online via Aalto lib})}\) \(\newcommand{\SW}{\href{http://algs4.cs.princeton.edu/home/}{Algorithms, 4th ed.}}\) \(%\newcommand{\SW}{\href{http://algs4.cs.princeton.edu/home/}{Sedgewick and Wayne}}\) \(\) \(\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{\BigOh}{\mathcal{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

The visiting orders for the nodes in the tree shown below 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 \)

_images/trees-binary-6.png

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 Negate(expr: Expr) extends Expr {
  def prefixStr: String = "Negate("+expr.prefixStr+")"
  def infixStr: String = "-"+expr.infixStr
  def postfixStr: String = expr.postfixStr + " -"
}
case class Add(left: Expr, right: Expr) extends Expr {
  def prefixStr: String = "Add("+left.prefixStr+","+right.prefixStr+")"
  def infixStr: String = "("+left.infixStr+"+"+right.infixStr+")"
  def postfixStr: String = left.postfixStr+" "+right.postfixStr+" +"
}
case class Multiply(left: Expr, right: Expr) extends Expr {
  def prefixStr: String = "Multiply("+left.prefixStr+","+right.prefixStr+")"
  def infixStr: String = "("+left.infixStr+"*"+right.infixStr+")"
  def postfixStr: String = left.postfixStr + " "+ right.postfixStr + " *"
}
case class Var(name: String) extends Expr {
  def prefixStr: String = "Var(\""+name+"\")"
  def infixStr: String = name
  def postfixStr: String = name
}
case class Num(value: Double) extends Expr {
  def prefixStr: String = "Num("+value.toString+")"
  def infixStr: String = value.toString
  def postfixStr: String = value.toString
}

val e = Negate(Add(Multiply(Num(2.0),Var("x")),Var("y")))
println(e.prefixStr)
println(e.infixStr)
println(e.postfixStr)

The parse tree corresponding to the expression \( -(2.0x + y) \) is 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).