Recursive data structures noter ch.3 Modeling recursive structure by class hierarchy Recursive traversal of structure
Recursive data structuresnoter ch.3
Modeling recursive structure by class hierarchy
Recursive traversal of structure
Recursive data structure• Recursive 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
• Building a recursive structure– Parsing using mutually recursive methods
File system
File system
• A directory containing (smaller) file systems
• Or a single file
Arithmetic expression
• An expression is either– a constant, or– an operator and two smaller expressions
Expression as binary tree
• Recursive structureNode
Leaf
A binary tree is• an internal node (root)
and two smaller trees, or• a leaf
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: Operatorpublic enum Operator {PLUS("+"), MINUS("-"), MULT("*"), DIV("/");private String name;private Operator(String name) { this.name = name; }public String toString() { return name; }public static Operator parseOp(String s) {
if (Operator.PLUS.name.equals(s)) return Operator.PLUS;if (Operator.MINUS.name.equals(s)) return Operator.MINUS;if (Operator.MULT.name.equals(s)) return Operator.MULT;if (Operator.DIV.name.equals(s)) return Operator.DIV;throw new UnsupportedOperationException(s);
}public int apply(int left, int right) {
switch (this) {case PLUS: return left + right; case MINUS: return left - right; case MULT: return left * right; case DIV: return left / right; default:
throw new UnsupportedOperationException(this.toString());}
}}
representation of an expression
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)
));
Recursive bullet list
• In webbrowser • html source code<ul>
<li>a simple bullet list</li><li>containing smaller lists</li><li><ul>
<li>a smaller sublist</li><li>
<ul><li>a tiny list</li><li>with several entries</li>
</ul></li><li>look: recursive lists!</li>
</ul></li>
</ul>
QUIZ UML and recursion
Which UML diagram models recursive bullet lists best?
1.
4.
2.
3.
5. I don’t 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
elsex = 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();Tree r = ((Node)w).getRight();Operator o = ((Node)w).getOp();int left_answer = evaluate(l);int right_answer = evaluate(r);answer = o.apply(left_answer,right_answer);
}return answer;
}
instanceof-test necessary
Java technicality:lots of casts obscures the code
Recursive bullet list• In webbrowser • html source code
<ul><li>a simple bullet list</li><li>containing smaller lists</li><li><ul>
<li>a smaller sublist</li><li>
<ul><li>a tiny list</li><li>with several entries</li>
</ul></li><li>look: recursive lists!</li>
</ul></li>
</ul>
• UML model
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;
}
How should the compiler errors be fixed?1. There should be no errors – update java compiler to newer version!2. Declare getText() and getEntries() in interface HTML3. Type cast h to Text and BulletList, respectively4. Fix in some other way5. I don’t know
QUIZTraversal by externalrecursive method
internal mutually recursive methods• Ensure that all classes implementing Tree define a getValue method
• In interface Treepublic abstract int getValue();
• in class Leaf:public int getValue() { return value; }
• in class Node:public int getValue() {
return op.apply(left.getValue(),right.getValue());
}
instanceof-tests and casts are no longer
necessary!
Node expr1 =new Node(new Leaf(8),Operator.MULT,new Node(new Leaf(5),Operator.PLUS,new Leaf(2)
));
Example: 8 * (5 + 2)
• in class Leaf:public int getValue() { return value; }
• in class Node:public int getValue() {
int l = left.getValue();int r = right.getValue();return op.apply(l,r);
}
Example: 8 * (5 + 2)expr1.getValue()
Example: 8 * (5 + 2)expr1.getValue()
Example: 8 * (5 + 2)expr1.getValue()
Example: 8 * (5 + 2)expr1.getValue()
Example: 8 * (5 + 2)expr1.getValue()
Example: 8 * (5 + 2)expr1.getValue()
Example: 8 * (5 + 2)expr1.getValue()
Example: 8 * (5 + 2)expr1.getValue()
Recursive bullet list• In webbrowser • html source code
<ul><li>a simple bullet list</li><li>containing smaller lists</li><li><ul>
<li>a smaller sublist</li><li>
<ul><li>a tiny list</li><li>with several entries</li>
</ul></li><li>look: recursive lists!</li>
</ul></li>
</ul>
• UML model
QUIZ
Code in class BulletList:
public String getText() {String result = "<ul>";for (HTML h : getEntries())
result += "<li>"+h.getText()+"</li>";return result+"</ul>";
}
Traversal by internal recursive method
How should the compiler error be fixed?1. There should be no errors – update java
compiler to newer version!2. Declare getText() in interface HTML3. Type cast h to Text4. Type cast h to BulletList5. Fix in some other way6. I don’t know
Comparing traversal techniques
• external recursive method:– obscures code by instanceof test and casts
• internal mutually recursive methods:– for each new kind of traversal it is necessary to mess
around with the code of all classes to insert new methods
• 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
• EvaluateVisitor is the client.• Mutually recursive accept / visitNode• Recursion stops when calling visitLeaf
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 Treepublic <T> T accept(TreeVisitor<T> v) ;
• In class Leafpublic <T> T accept(TreeVisitor<T> v){return v.visitLeaf(this);
}
• In class Nodepublic <T> T accept(TreeVisitor<T> v){return v.visitNode(this);
}
callback to problem specific method
callback to problem specific methods defined
by external visitor
Problem specific TreeVisitor• A problem specific traversal requires an implementation
of interface TreeVisitor:public interface TreeVisitor<T> {
public T visitLeaf(Leaf l);public T visitNode(Node n);
}
• 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
• instanceof test not needed (handled by call back)
class EvaluateVisitor implements TreeVisitor<Integer> {
public Integer visitLeaf(Leaf 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);
}}
• In class EvaluateVisitorpublic Integer visitLeaf(Leaf 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);
}• In class Leafpublic <T> T accept(TreeVisitor<T> v){return v.visitLeaf(this);
}
• In class Nodepublic <T> T accept(TreeVisitor<T> v){return v.visitNode(this);
}
Example: 8 * (5 + 2)expr1.accept(new EvaluateVisitor())
Example: 8 * (5 + 2)expr1.accept(new EvaluateVisitor())
Example: 8 * (5 + 2)expr1.accept(new EvaluateVisitor())
Example: 8 * (5 + 2)expr1.accept(new EvaluateVisitor())
Example: 8 * (5 + 2)expr1.accept(new EvaluateVisitor())
Example: 8 * (5 + 2)expr1.accept(new EvaluateVisitor())
Example: 8 * (5 + 2)expr1.accept(new EvaluateVisitor())
Example: 8 * (5 + 2)expr1.accept(new EvaluateVisitor())
Example: Expression evaluation
• Given some treeTree t = ...
• Evaluate by external recursive methodevaluate(t)
• or by internal mutually recursive methodst.getValue()
• or by using visitor patternt.accept(new EvaluateVisitor())
Recursive bullet list• In webbrowser • html source code
<ul><li>a simple bullet list</li><li>containing smaller lists</li><li><ul>
<li>a smaller sublist</li><li>
<ul><li>a tiny list</li><li>with several entries</li>
</ul></li><li>look: recursive lists!</li>
</ul></li>
</ul>
• UML model
QUIZ
public class PrintVisitor implements HTMLVisitor<String> {
public String visitText(Text t) { return t.getText(); }
public String visitBulletList(BulletList b) {String result = "<ul>";for (HTML h : b.getEntries()) result += "<li>"+ +"</li>";return result+"</ul>”;
}}
What code should replace ?1. b.getText()2. b.accept(this)3. b.accept(new PrintVisitor());4. h.getText()5. h.accept(this)6. h.accept(new PrintVisitor());7. None of the above8. I don’t know
Traversal by visitor
traversal: printing expression• in order traversal: visit left child (subexpression) before
visiting root node (operator), and finally visit right child
text(v):if v is a leaf:return number
elsereturn "("+ text( left subexpression)+ operator+ text( right subexpression )+ ")"
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();
}
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 );
elseincrement y;draw( left subexpression );decrement y;drawSymbol( operator );increment y;draw( right subexpression );decrement y;
pseudocode ignores connection lines.
Adding connection lines to drawingstate : a current drawing position (x,y)
initially (x,y) = (0,0)drawSymbol(s): // returns position where s is drawnincrement x and draw s;return (x,y)
draw(v): // returns where root of expression is drawnif v is a leaf:return drawSymbol( number );
elseincrement y;l = draw( left subexpression );decrement y;c = drawSymbol( operator );draw line from l to c;increment y;r = draw( right subexpression );decrement y;draw line from r to c;return c;
drawing of connection lines requires that
draw methods return positions for later use
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.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);
}}
... implements TreeVisitorprivate 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;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 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)));
Recursive bullet list• In webbrowser • html source code
<ul><li>a simple bullet list</li><li>containing smaller lists</li><li><ul>
<li>a smaller sublist</li><li>
<ul><li>a tiny list</li><li>with several entries</li>
</ul></li><li>look: recursive lists!</li>
</ul></li>
</ul>
• UML model
QUIZ
public class PrintVisitor implements HTMLVisitor<String> {
public String visitText(Text t) { return t.getText(); }
public String visitBulletList(BulletList b) {String result = "<ul>";for (HTML h : b.getEntries())
result += "<li>"+h.accept(this)+"</li>";return result+"</ul>”;
}} How would you declare accept in interface HTML?
1. public <E> E accept(HTMLVisitor<E> v);2. public E accept(HTMLVisitor<E> v);3. public String accept(HTMLVisitor<String> v);4. public String accept(PrintVisitor v);5. I don’t know
Traversal by visitor
Parsing an expression
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)
));
Easier:
Tree t = new Parser(“6+(8*2-1)”).parseExpression();
Parsing an expression
• Problem:– build the recursive data structure for
arithmetic expressions such as3 + 4 * 5
(3 + 4) * 51 – (2 – (3 – (4 – 5)))
• Precedence rules: – * and / take precedence over + and –– may overrule using parentheses ( ... )
Syntax diagram for expression
number
Syntax tree for two expressions
Mutually recursive methods
• Implement 3 methods that call each other recursivelyparseExpressionparseTermparseFactor
• An ExpressionTokenizer is used to group input in tokens. A token being a string of digits or one of "+", "-", "*", "/", "(", ")". Methods:peekTokennextToken
public class Expression Parser {public ExpressionParser(String anExpression) {
tokenizer = new ExpressionTokenizer(anExpression);}
public Tree parseExpression() { ... }
public Tree parseTerm() { ... }
public Tree parseFactor() { ... }
private ExpressionTokenizer tokenizer;}
public Tree parseExpression() {Tree t = parseTerm();while ("+".equals(tokenizer.peekToken())
|| "-".equals(tokenizer.peekToken())) {Operator op = Operator.parseOp(
tokenizer.nextToken());Tree t2 = parseTerm();t = new Node(t,op,t2);
}return t;
}
public int parseTerm() {Tree t = parseFactor();while ("*".equals(tokenizer.peekToken())
|| "/".equals(tokenizer.peekToken())) {Operator op = Operator.parseOp(
tokenizer.nextToken());Tree t2 = parseFactor();t = new Node(t,op,t2);
}return t;
}
public int parseFactor() {Tree t;if ("(".equals(tokenizer.peekToken())) {
tokenizer.nextToken();t = parseExpression();tokenizer.nextToken(); // read ")"
} elset = new Leaf(
Integer.parseInt(tokenizer.nextToken()));return t;
}
QUIZpublic Tree parseTerm() { }
if ("!".equals(tokenizer.peekToken())) {tokenizer.nextToken();return new BoolNode(
BoolOperator.NOT,parseFactor());}return parseFactor();
BoolTree t = parseFactor();if ("!".equals(tokenizer.peekToken())) {
tokenizer.nextToken();t = new BoolNode(BoolOperator.NOT,t);
}return t;
a
b
(Part of) syntax diagram for Boolean expression
Which code could replace ?
1. a2. b3. a and b4. Neither a nor b5. I don’t know
Parse Expression