You are on page 1of 8

Recursive data structure

Recursive structure:

Recursive data structures


noter ch.3
Modeling recursive structure by
class hierarchy
Recursive traversal of structure

list, tree

Object oriented representation


Interface
Implementing classes

Traversal of recursive structure


External recursive method
Internal recursive method (Composite design pattern)
Visitor design pattern

File system

single file

or a directory containing (smaller) file


systems

Binary tree
a leaf

or an internal node
(root) and two smaller
trees

Binary tree example: recursive


expression
An expression is either

Recursive structure

a constant, or
an operator and two smaller expressions

Classes for modeling recursive


expression
public interface Tree { }
public class Leaf implements Tree {
private int value;
public Leaf(int n) { value = n; }
public int getValue() { return value; }
}
public class Node implements Tree {
private Operator op;
private Tree left;
private Tree right;
public Node(Tree l, Operator o, Tree r)
{ op = o; left = l; right = r; }
public Operator getOp() { return op; }
public Tree getLeft() { return left; }
public Tree getRight() { return right; }
}

Enumeration type: Operator


Recall how to make enumeration type
public enum Operator {
PLUS("+"), MINUS("-"), MULT("*"), DIV("/");
private String name;
private Operator(String name) { this.name = name; }
public String toString() { return name; }
public int apply(int left, int right) {
if (this == Operator.PLUS) return left + right;
if (this == Operator.MINUS) return left - right;
if (this == Operator.MULT) return left * right;
/* this == Operator.DIV */ return left / right;
}
}

representation of an expression

QUIZ
Which UML diagram models
recursive bullet lists best?
2.

1.
Tree t =
new Node(
new Leaf(6),
Operator.PLUS,
new Node(
new Node(new Leaf(8),Operator.MULT,new Leaf(2)),
Operator.MINUS,
new Leaf(1)
)
);

3.

4.

5. I dont know

Traversal of recursive structure


traversal
calculate value of expression
print expression
traversal techniques
external recursive method
internal mutually recursive methods
(composite pattern)
visitor pattern

traversal: expression evaluation


post order traversal: visit children (subexpressions)
before visiting root node (operator)

evaluate(v):
if v is a leaf:
return number stored at v
else
x = evaluate(left subexpression stored at v)
y = evaluate(right subexpression stored at v)
return x o y (where o is operator stored at v)

evaluation by single external


recursive method
public int evaluate(Tree w) {
int answer;
if ( w instanceof Leaf ) answer = ((Leaf)w).getValue();
else {
Tree l = ((Node)w).getLeft();
instanceof-test necessary
Tree r = ((
((Node)w).getRight();
) ) g
g ();
Operator o = ((Node)w).getOp();
Java technicality:
int left_answer = evaluate(l);
lots of casts obscures the code
int right_answer = evaluate(r);
answer = o.apply(left_answer,right_answer);
}
return answer;
}

QUIZ

For QUIZ:

HTML source code

<ul>
<li>a simple bullet list</li>
<li>containing smaller lists</li>
<li>
<ul>
<li>a smaller sublist</li>
<li>
li
<ul>
<li>a tiny list</li>
<li>with several entries</li>
</ul>
</li>
<li>look: recursive lists!</li>
</ul>
</li>
</ul>

internal mutually recursive methods

Which if any errors arise?


1. Compiler error(s)
2. Runtime exceptions
3. No errors method is correct!
4. I dont know
public String print(HTML h) {
String result = "";
if (h instanceof Text) result = h.getText();
else {
result += "<ul>";
for (HTML k : h.getEntries())
result += "<li>"+print(k)+"</li>";
result += "</ul>";
}
return result;
}

Ensure that all classes implementing Tree define a


getValue method
instanceof-tests and
In interface Tree
casts are no longer
public abstract int getValue();

necessary!

in class Leaf:
public int getValue() { return value; }

in class Node:
public int getValue() {
return op.apply(left.getValue(),
right.getValue());
}

Example: 8 * (5 + 2)
expr1.getValue()
Example: 8 * (5 + 2)

Node expr1 =
new Node(
new Leaf(8),
Operator.MULT,
new Node(
new Leaf(5),
Operator.PLUS,
new Leaf(2)
)
);

QUIZ

Comparing traversal techniques

Which if any errors arise?


1. Compiler error(s)
2. Runtime exceptions
3. No errors!
4. I dont know

external recursive method:


obscures code by instanceof test and casts

internal mutually recursive methods:


for each new kind of traversal it is necessary
y to mess
around with the code of all classes to insert new
methods

Code in class BulletList:


public String getText() {
String result = "<ul>";
for (HTML h : getEntries())
result += "<li>"+h.getText()+"</li>";
return result+"</ul>";
}

Visitor pattern (avoids above problems):


inserts a single method in all classes once and for all
these methods make call back to problem specific
external methods

Visitor design pattern

Decoupling of Tree hierarchy and problem specific


traversal.
The Tree hierarchy is prepared by adding an accept
method capable of performing callback
A problem specific traversal (such as value computation)
requires an implementation of interface TreeVisitor

Modification of Tree classes

The recursive structure is prepared (once and for all) by adding an


accept method to Tree and all its implementing classes

In interface Tree

In class Leaf

public <T> T accept(TreeVisitor<T> v){


return v.visitLeaf(this);
}

In class Node

public <T> T accept(TreeVisitor<T> v){


return v.visitNode(this);
}

A problem specific traversal requires an implementation


of interface TreeVisitor:
public interface TreeVisitor<T> {
public T visitLeaf(Leaf l);
public T visitNode(Node n);
}

public <T> T accept(TreeVisitor<T> v) ;

Problem specific TreeVisitor

callback
callback to
to problem
problem
specific
specific
methods
method
defined
by external visitor

For traversal, the TreeVisitor methods send the tree


object an accept message.
The accept methods in turn make call back to the
appropriate visitLeaf or visitNode method
methods visitLeaf/visitNode and accept are
mutually recursive.

Visitor example: expression


evaluation

Example: 8 * (5 + 2)
expr1.accept(new EvaluateVisitor())

instanceof test not needed (handled by call back)


class EvaluateVisitor implements
TreeVisitor<Integer> {
pub c Integer
public
tege visitLeaf(Leaf
s t ea ( ea l)
) {
return l.getValue();
}
public Integer visitNode(Node n) {
int l = n.getLeft().accept(this);
int r = n.getRight().accept(this);
return n.getOp().apply(l,r);
}
}

QUIZ

Example: Expression evaluation


Given some tree
Tree t = ...

public class PrintVisitor implements HTMLVisitor<String> {

Evaluate by external recursive method

public String visitText(Text t) { return t.getText(); }

evaluate(t)
public
bli St
String
i
visitBulletList(BulletList
i itB ll tLi t(B ll tLi t b) {
String result = "<ul>";
for (HTML h : b.getEntries())
result += "<li>"+h.accept(this)+"</li>";
return result+"</ul>;
}

or by internal mutually recursive methods


t.getValue()

or by using visitor pattern


t.accept(new EvaluateVisitor())

1.
2.
3.
4.
5.

traversal: printing expression


in order traversal: visit left child (subexpression) before
visiting root node (operator), and finally visit right child

How would you declare accept in interface HTML?


public <E> E accept(HTMLVisitor<E> v);
public E accept(HTMLVisitor<E> v);
public String accept(HTMLVisitor<String> v);
public String accept(PrintVisitor v);
I dont know

Printing expression using visitor


Computing String representation of expression (printing)
class PrintVisitor implements TreeVisitor<String> {
public String visitLeaf(Leaf l) {
return new Integer(l.getValue()).toString();
}

text(v):
if v is a leaf:
return number
else
return "("
+ text( left subexpression)
+ operator
+ text( right subexpression )
+ ")"

public String visitNode(Node n) {


return ("(" + n.getLeft().accept(this)
+ n.getOp()
+ n.getRight().accept(this) + ")");
}
}

Application:
System.out.println(t.accept(new PrintVisitor()));

Traversal example: drawing


expression
state : a current drawing position (x,y)
initially (x,y) = (0,0)
drawSymbol(s):
increment x and draw s;
draw(v):
if v is a leaf:
drawSymbol( number );
else
increment y;
draw( left subexpression );
decrement y;
drawSymbol( operator );
increment y;
draw( right subexpression );
decrement y;

pseudocode ignores connection lines.

Adding connection lines to drawing


state : a current drawing position (x,y)
initially (x,y) = (0,0)
drawSymbol(s): // returns position where s is drawn
increment x and draw s;
return (x,y)
draw(v): // returns where root of expression is drawn
if v is a leaf:
return drawSymbol( number );
else
increment y;
l = draw( left subexpression );
decrement y;
c = drawSymbol( operator );
draw line from l to c;
drawing of connection
increment y;
lines requires that
r = draw( right subexpression );
draw methods return
decrement y;
positions for later use
draw line from r to c;
return c;

... implements TreeVisitor

class Draw ...


class DrawVisitor extends JComponent implements
TreeVisitor<Point> {
private static final int UNIT = 30;
private Tree t;
private Point pen_pos;
private Graphics2D g;
public DrawVisitor(Tree t) {
this.t = t;
JFrame f = new JFrame();
f add(this)
f.add(this);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(400,400);
f.setVisible(true);
}
...
public void paintComponent(Graphics g) {
this.g = (Graphics2D)g;
pen_pos = new Point(UNIT,UNIT);
t.accept(this);
}
}

private Point drawSymbol(Object ob) {


pen_pos.x += UNIT;
g.drawString(ob.toString(),pen_pos.x,pen_pos.y-4);
return (Point) pen_pos.clone();
}
public Point visitLeaf(Leaf l) {
return drawSymbol( new Integer(l.getValue()) );
}
public Point visitNode(Node n) {
pen pos y += UNIT;
pen_pos.y
Point left_pos = n.getLeft().accept(this);
pen_pos.y -= UNIT;
Point node = drawSymbol(n.getOp());
g.draw(new Line2D.Double(left_pos,node));
pen_pos.y += UNIT;
Point right_pos = n.getRight().accept(this);
pen_pos.y -= UNIT;
g.draw(new Line2D.Double(right_pos,node));
return node;
}

Actual drawing made by

Recursive list

new DrawVisitor(t)

where
Tree t = new Node(new Leaf(6),Operator.PLUS,
new Node(new Node(new Leaf(8),Operator.MULT,
new Leaf(2)),Operator.MINUS,new Leaf(1)));

the empty list

or an element followed
by a shorter list

[]

[ 2, 7, 13, 1]

class hierarchy representing list


Interface
public interface ConsList {}

class representing empty list


public class Nil implements ConsList {}

class representing
p
g element and shorter list
public class Cons implements ConsList {
private Object hd;
private ConsList tl;
public Cons(Object x, ConsList y) { hd = x; tl = y; }
}

The list ["Easter","Xmas"] may be represented as

public interface ConsListVisitor<T> {


public T visitNil(Nil n);
public T visitCons(Cons c);
}

new Cons("Easter",new Cons("Xmas",new Nil())).

Problem Specific ConsListVisitor:


Linear Search

ConsList classes prepared for visits


The recursive structure is prepared (once and for all) by
adding an accept method

public class SearchVisitor implements


ConsListVisitor<Boolean> {
private Object key;
public SearchVisitor(Object k) { key = k; }

In interface ConsList
abstract <T> T accept(ConsListVisitor<T> v);

public Boolean visitNil(Nil n) { return false; }

In class Nil

public Boolean visitCons(Cons c) {


return c.head().equals(key) || c.tail().accept(this);
}

public <T> T accept(ConsListVisitor<T> v) {


return v.visitNil(this);
callback
callback to
to problem
problem
}

specific
specific
methods
method
defined
by external visitor

In class Cons

Search in recursive list l by


l.accept(new SearchVisitor("Xmas"));

public <T> T accept(ConsListVisitor<T> v) {


return v.visitCons(this);
}

Recursive labyrinth: solving it while


constructing it...

(simple) labyrinth

empty labyrinth

or a wall and two smaller


labyrinths

...solving it while constructing it

You might also like