\(\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.
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.
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).