Recursion Programming –Method calling itself. –On a smaller problem. –Alternative to loops....

173
Recursion • Programming Method calling itself. On a smaller problem. Alternative to loops. English definitions: adequate: satisfactory satisfactory: adequate recursion: recursion • Mathematics expression giving successive terms of a series (Oxford) • Grammar procedure repeating itself indefinitely or until condition met, such as grammar rule (Webster)
  • date post

    19-Dec-2015
  • Category

    Documents

  • view

    223
  • download

    0

Transcript of Recursion Programming –Method calling itself. –On a smaller problem. –Alternative to loops....

Recursion• Programming

– Method calling itself.

– On a smaller problem.

– Alternative to loops.

• English definitions:– adequate: satisfactory

– satisfactory: adequate

– recursion: recursion

• Mathematics– expression giving successive terms of a series (Oxford)

• Grammar

– procedure repeating itself indefinitely or until condition met, such as grammar rule (Webster)

Grammars• Noun Phrases

– boy

– little boy– smart little boy– naughty smart little boy

• Structure decompositions formally described by grammar rules– <Noun Phrase> <Noun>– <Noun Phrase>

<Adjective> <Noun Phrase>• Words within angle brackets called

non-terminals– think of them as types

• There may be multiple rules describing a non-terminal

• Rules describe valid sequences of terminals

– naughty smart little boy– think of terminals as type instances

<Noun Phrase>

boy

<Adjective> <Noun Phrase>

boy

<Noun>

little boy

little

Smart little boy

<Adjective>

smart

Recursive definition

<Noun Phrase>

Recursive Methods

• Recursive Functions and Procedures

• Number-based Recursion

• List-based Recursion

• Tree-based Recursion

factoroial (n)public static int factorial (int n) { int product = 1; while (n > 0) { product *= n; n -= 1; } return product; }

public static void main (String[] args) {while (true) {// loop condition never false

int n = readInt();if (n < 0)

break;System.out.println(“factorial =“ + factorial(n);

} }

1*2*3*4 … n

Defining factorial(n)

Product of the first n numbers.

1*2*3*4 … n

factorial (0) = 1

factorial (1) = 1 = 1* factorial(0)

factorial (2) = 2*1 = 2* factorial(1)

factorial (3) = 3*2*1 = 3* factorial(2)

factorial (4) = 4*3*2*1 = 4* factorial(3)

factorial (n) = n*n-1*..*1 = n* factorial(n-1)

Defining factorial(n)

factorial (n) = 1

factorial (n) = n* factorial(n-1)

if n == 0

if n > 0

Implementing factorial(n)

factorial (n) = 1

factorial (n) = n* factorial(n-1)

if n == 0

if n > 0

public static int factorial (int n) { if (n == 0)

return 1; if (n > 0)

return n*factorial(n-1); }

Function must return something for all cases

n < 0 ?

Implementing factorial(n)

factorial (n) = 1

factorial (n) = n* factorial(n-1)

if n == 0

if n > 0

public static int factorial (int n) { if (n == 0)

return 1; else if (n < 0)

return factorial(-n); else

return n*factorial(n-1); }

Recursive reduction steps

Base case

factorial (n) = factorial(-n) if n < 0

General form of Recursive Methodif (base case 1 ) return solution for base case 1else if (base case 2) return solution for base case 2….else if (base case n) return solution for base case nelse if (recursive case 1) do some preprocessing recurse on reduced problem do some postprocessing…else if (recursive case m) do some preprocessing recurse on reduced problem do some postprocessing

Recursion Vs Loops (Iteration)

public static int factorial (int n) { if (n == 0)

return 1; else if (n < 0)

return factorial(-n); else

return n*factorial(n-1); }

public static int factorial (int n) { int product = 1; while (n > 0) { product *= n; n -= 1; } return product; }

Implementation follows from definition.

Tracing Recursive Calls

Stack

Tracing Recursive Calls

Invocation n return valuefactorial(1) 1 ?factorial(2) 2 ?

Invocation n return valuefactorial(0) 0 ?factorial(1) 1 ?factorial(2) 2 ?

Invocation n return valuefactorial(0) 0 1factorial(1) 1 ?factorial(2) 2 ?

Invocation n return valuefactorial(0) 0 1factorial(1) 1 1factorial(2) 2 ?

Invocation n return valuefactorial(0) 0 1factorial(1) 1 1factorial(2) 2 2

Recursion Pitfalls

public static int factorial (int n) {

return n*factorial(n-1); }

factorial (2)

2* factorial (1)

1* factorial (0)

0* factorial (-1)

-1 * factorial(-2)Infinite recursion! (Stack overflow)

No base case....

Recursion Pitfalls

factorial (2)

factorial (3) / 3

factorial (4) / 4

factorial (5) / 5

factorial(6) / 6Infinite recursion!

Recurses on bigger problem....

public static int factorial (int n) { if (n == 0)

return 1; else if (n < 0)

return factorial(-n); else

return factorial(n+1)/(n+1); }

Recursive Methods

• Should have base case(s)

• Recurse on smaller problem(s) - recursive calls should converge to base case(s)

Recursive Functions with Multiple Parameters

power (base, exponent)

base*base*base*…*base

power (0, exponent) = 0

exponent # of times

baseexponent

power (1, exponent) = 1power (2, exponent) = 2*2*2…*2 (exponent times)power (3, exponent) = 3*3*3…*3 (exponent times)

No pattern!

Recursive Functions with Multiple Parameters

power (base, exponent)

base*base*base*…*base

exponent # of times

baseexponent

power (base, 0) = 1

power (base, 1) = base*1 = base* power(base, 0)

power (base, 2) = base*base*1 = base* power(base, 1)

power (base, exponent) = base*power(base, exponent-1)

Defining power(base, exponent)

power (base, exponent) = 1 if exponent <= 0

power (base, exponent) = base*power(base, exponent-1) if exponent <= 0

public static int power (int base, exponent) { if (n <= 0)

return base; else

return base*power(base, exponent-1); }

Recursive Procedures: greet(n)

greet (1)

print “hello”

greet (0) greet (2) greet(n)

n times

print “hello”

print “hello”

print “hello”

print “hello”

print “hello”

print “hello”

Defining greet(n) (edit)

greet (1)

print “hello”

greet (0) greet (2) greet(n)

n times

print “hello”

print “hello”

print “hello”

print “hello”

print “hello”

print “hello”

Defining greet(n) (edited)

greet (1)

print “hello”

greet (0) greet (2) greet(n)

n times

print “hello”

print “hello”

print “hello”

print “hello”

print “hello”

print “hello”

Do nothing

Greet(0)

Print hello Greet(1)

Print hello

Defining greet(n)

greet (1)

print “hello”

greet (0) greet (2) greet(n)

n times

print “hello”

print “hello”

print “hello”

print “hello”

print “hello”

print “hello”greet(0);

print “hello”; greet(1);

print “hello”;

do nothing;

greet(n-1);

print “hello”;

Defining greet(n)

greet(n) if n <= 0

greet(n) if n > 0

do nothing;

greet(n-1); print “hello”

Implementing greet(n)

greet(n) if n <= 0

greet(n) if n > 0

public static void greet (int n) { if (n > 0) {

greet(n-1);System.out.println(“hello”);

}

do nothing;

greet(n-1); print “hello”

List-based recursion

• List– Collection objects– Enumerations– Streams

• Base case– Work on some items in the list

• Reducing a list for recursion– Working on remainder of the list

List-based recursion: multiplyList()

multiplyList ({-1}) = 1 if remaining input is: -1

multiplyList ({2 -1}) = 2 if remaining input is: 2 -1

multiplyList ({6 2 -1})= 2*6 if remaining input is: 6 2 -1

multiplyList(): informal defn

• Multiply an input stream of numbers ending with a –1 sentinel.

• multiplyList({a1, a2, a3, …, aN, -1}) = a1*a2…aN

• multiplyList({-1}) = 1;

multiplyList(): formal defn (edit)

• Multiply an input stream of numbers ending with a –1 sentinel.

• multiplyList({a1, a2, a3, …, aN, -1}) = a1*a2…aN

• multiplyList({-1}) = 1;

• multiplyList(inputStream)

multiplyList(): formal defn (edited)

• Multiply an input stream of numbers ending with a –1 sentinel.

• multiplyList({a1, a2, a3, …, aN, -1}) = a1*a2…aN

• multiplyList({-1}) = 1;

• multiplyList(inputStream) {– int nextVal = readNextVal(inputStream);

– if (nextVal == -1) return 1;

– return nextVal*multiplyList(inputStream);

multiplyList(): formal definition

multiplyList (inputStream) = 1 if nextVal < 0

multiplyList (inputStream)= readNextVal()*multiplyList(inputStream) if nextVal > 0

public static int multiplyList (BufferReader inputStream) { int nextVal = readNextVal(inputStream); if (nextVal < 0) return 1; else return nextVal*multiplyList(inputStream) }

Tracing multiplyList()

public static int multiplyList (BufferReader inputStream) { int nextVal = readNextVal(inputStream); if (nextVal < 0) return 1; else return nextVal*multiplyList() }

Invocation Remaininginput

return value

multiplyList() 2 30 -1 ???

Invocation Remaininginput

return value

multiplyList() 30 -1 ???multiplyList() 2 30 -1 ???

Invocation Remaininginput

return value

multiplyList() -1 ???multiplyList() 30 -1 ???multiplyList() 2 30 -1 ???

Invocation Remaininginput

return value

multiplyList() -1 1multiplyList() 30 -1 ???multiplyList() 2 30 -1 ???

Invocation Remaininginput

return value

multiplyList() -1 1multiplyList() 30 -1 30multiplyList() 2 30 -1 ???

Invocation Remaininginput

return value

multiplyList() -1 1multiplyList() 30 -1 30multiplyList() 2 30 -1 60

Recursion initiator

public static int multiplyInputs() { return multiplyList(new BufferReader(new InputStreamReader(System.in)));}

Printing an Enumeration – Iterative Solution

static void print(StringHistory strings) {System.out.println("******************");StringEnumeration stringEnumeration = strings.elements();while (stringEnumeration.hasMoreElements()) {

System.out.println(stringEnumeration.nextElement());}System.out.println("******************");

}

Printing an Enumeration – Recursive Solution (edit)

//edit thisstatic void print(StringHistory strings) {

System.out.println("******************");StringEnumeration stringEnumeration = strings.elements();while (stringEnumeration.hasMoreElements()) {

System.out.println(stringEnumeration.nextElement());}System.out.println("******************");

}

//edit thisstatic void print(StringHistory strings) {

System.out.println("******************");StringEnumeration stringEnumeration = strings.elements();while (stringEnumeration.hasMoreElements()) {

System.out.println(stringEnumeration.nextElement());}System.out.println("******************");

}

Printing an Enumeration – Recursive Solution (edited)

//edit thisstatic void print(StringHistory strings) {

System.out.println("******************");StringEnumeration stringEnumeration = strings.elements();print(stringEnumeration);System.out.println("******************");

}

//edit thisstatic void print(StringEnumeration stringEnumeration) { if (stringEnumeration.hasMoreElements()) {

System.out.println(stringEnumeration.nextElement());print(stringEnumeration);

}}

Printing an Enumeration – Recursive Solution

static void print(StringHistory strings) {System.out.println("******************");print (strings.elements());System.out.println("******************");

}

static void print (StringEnumeration stringEnumeration) {if (!stringEnumeration.hasMoreElements()) return;System.out.println(stringEnumeration.nextElement());print (stringEnumeration);

}

Printing an Indexed List– Iterative Solutionstatic void print(StringHistory strings) {

System.out.println("******************");int elementNum = 0;while (elementNum < strings.size()) {

System.out.println(strings.elementAt(elementNum));elementNum++;

}System.out.println("******************");

}

Printing an Indexed List – Recursive Solution (edit)static void print(StringHistory strings) {

System.out.println("******************");int elementNum = 0;while (elementNum < strings.size()) {

System.out.println(strings.elementAt(elementNum));elementNum++;

}System.out.println("******************");

}

static void print(StringHistory strings) {System.out.println("******************");int elementNum = 0;while (elementNum < strings.size()) {

System.out.println(strings.elementAt(elementNum));elementNum++;

}System.out.println("******************");

}

Printing an Indexed List – Recursive Solution (edited)

static void print(StringHistory strings) {System.out.println("******************");print(strings, 0);System.out.println("******************");

}

static void print(StringHistory strings, int elementNum) {if (elementNo == strings.size()) return;System.out.println(strings.elementAt(elementNum));print(strings, elementNum++);

}

Printing an Indexed List – Recursive Solution

static void print(StringHistory strings) {System.out.println("******************");print (strings, 0);System.out.println("******************");

}

static void print (StringHistory strings, int elementNo) {if (elementNo == strings.size()) return;System.out.println(strings.elementAt(elementNo));print (strings, elementNo + 1);

}

Var + 1 vs. Var++static void printEnumeration(StringHistory strings) {

//System.out.println("vector recursive");System.out.println("******************");print (strings, 0);System.out.println("******************");

}

static void print (StringHistory strings, int elementNo) {if (elementNo == strings.size()) return;System.out.println(strings.elementAt(elementNo));print (strings, elementNo++);

}

Redundant assignment

Incremented after recursive calInfinite recursion

Printing an Indexed List – Recursive Solution

static void printEnumeration(StringHistory strings) {//System.out.println("vector recursive");System.out.println("******************");print (strings, 0);System.out.println("******************");

}

static void print (StringHistory strings, int elementNo) {if (elementNo == strings.size()) return;System.out.println(strings.elementAt(elementNo));print (strings, ++elementNo);

}

Redundant assignment

Incremented before recursive cal

Functional Languages

• Only recursion, no iteration (loops).

• No assignment!– All variables are final.– Single assignment languages.– No incrementing of loop variable.

• Elaborate support for lists.

List-based Recursion

static void print (StringHistory strings, int elementNo) {if (elementNo == strings.size()) return;System.out.println(strings.elementAt(elementNo));print (strings, elementNo + 1);

}

static void print (StringEnumeration stringEnumeration) {if (!stringEnumeration.hasMoreElements()) return;System.out.println(stringEnumeration.nextElement());print (stringEnumeration);

}

public static int multiplyList (BufferReader inputStream) { int nextVal = readInt(inputStream); if (nextVal < 0) return 1; else return nextVal*multiplyList(inputStream) }

List

Head

Tail

Base: process head

RecurseOn: tail

List-based Recursion

• Function gets list as parameter• Divides list into head and tail.• Processes head in base case.• Returns if empty tail.• Recurses on non-empty tail.• General function structure

m (List l)if l.isEmpty() return;process l.head();m(l.tail()); Can be done in opposite order

Lists in functional and other languages

• One type representing lists– Head– Tail– isEmpty

• All lists instances of this class.

• Inefficient– Tail is copy of original

items

• Multiple representations of list– Stream-based

– Enumerations

– Vector-based

– Array-based

– StringHistory-based

– …

• Awkward (but more efficient) representations– Vector + index

Iterative Match Titlepublic Course matchTitle (String theTitle) {

for (int courseIndex = 0; courseIndex < size; courseIndex++) {if (contents[courseIndex].getTitle().equals(theTitle))

return contents[courseIndex];}return null;

}

Recursive Algorithm in terms of head and tail (edit)

Course matchTitle (title, courses)

Recursive Algorithm in terms of head and tail (edited)

Course matchTitle (title, courses)

if courses.isEmpty() return null;

if (title.equals(courses.head().getTitle())

return courses.head()

else

return matchTitle(title, courses.tail());

Recursive Algorithm in terms of head and tail

Course matchTitle (title, courses) if courses.isEmpty() return null;if title equals courses.head().getTitle()

return courses.head()else

return matchTitle(title, courses.tail())

Recursive Match Title

public Course matchTitle (String theTitle) {

return matchTitle(theTitle, 0, contents);

}

public Course matchTitle (String theTitle, int courseIndex, Course[] contents) {

if (courseIndex == size) return null;if (contents[courseIndex].getTitle().equals(theTitle))

return contents[courseIndex];return matchTitle(theTitle, courseIndex + 1, contents);

}

Does not change

Recursive Match Title

public Course matchTitle (String theTitle) {

return matchTitle(theTitle, 0);

}

public Course matchTitle (String theTitle, int courseIndex) {if (courseIndex == size) return null;if (contents[courseIndex].getTitle().equals(theTitle))

return contents[courseIndex];return matchTitle(theTitle, courseIndex + 1);

}

Global instance variable

Recursion vs. Iteration• Recursive solutions may be a little cleaner

than iterative solutions– Maybe not cleaner in list-based case because of

awkward representation

• Solution same as definition– formal definition problem– easier to get right

• Are there problems where recursive solution is much simpler?

Printing an enumeration in reverse order

static void print (StringEnumeration stringEnumeration) {if (!stringEnumeration.hasMoreElements()) return; System.out.println(stringEnumeration.nextElement());print (stringEnumeration);

}

static void print (StringEnumeration stringEnumeration) {if (!stringEnumeration.hasMoreElements()) return; print (stringEnumeration);System.out.println(stringEnumeration.nextElement());

}

In order

Reverse order

Printing an Enumeration in reverse order – loop solution

static void print(StringHistory strings) {System.out.println("******************");StringEnumeration stringEnumeration = strings.elements();while (stringEnumeration.hasMoreElements()) {

System.out.println(stringEnumeration.nextElement());}System.out.println("******************");

}

In order

Loop would have to store all items in some collection object (stack) that allows items to be accessed in reverse order.

Stack • Push– Pushes an item above

existing items

• Pop– Removes the top item– Last in first out (LIFO)

• Top– Returns the top item

• isEmpty– Returns true if no

elements.

• Procedure call stack– Last procedure in call

chain returns first

A

push (A)

B

push (B)

top

Stack • Push– Pushes an item above

existing items

• Pop– Removes the top item– Last in first out

(LIFO)

• Top– Returns the top item

• isEmpty– Returns true if no

elements.

• Procedure call stack– Last procedure in call

chain returns first

A

push (A) push (B)

top pop ()

Printing an Enumeration in reverse order – loop solution (edit)

static void print(StringHistory strings) {System.out.println("******************");StringEnumeration stringEnumeration = strings.elements();while (stringEnumeration.hasMoreElements()) {

System.out.println(stringEnumeration.nextElement());}System.out.println("******************");

}

Printing an Enumeration in reverse order – loop solution (edited)static void print(StringHistory strings) {

Stack s = new AStack();System.out.println("******************");StringEnumeration stringEnumeration = strings.elements();while (stringEnumeration.hasMoreElements()) {

s.push(stringEnumeration.nextElement();}while (!s.isEmpty()) {

System.out.println(s.top());s.pop();

}System.out.println("******************");

}

Printing an Enumeration in reverse order – loop solutionstatic void print(StringHistory strings) {

StringStack stringStack = new AStringStack();System.out.println("******************");StringEnumeration stringEnumeration = strings.elements(); while (stringEnumeration.hasMoreElements()) {

stringStack.push(stringEnumeration.nextElement());}while (!stringStack.isEmpty()) {

System.out.println(stringStack.top());stringStack.pop();

}System.out.println("******************");

}

Printing an enumeration in reverse order

• Recursive solution is easier as it uses the call stack created automatically.

• Loop uses a manually created stack.

Printing an Object Array

static Object[] introProg = {new Integer(14), "Intro. Prog.", "COMP"};

System.out.println(introProg);

[Ljava.lang.Object;@3f5d07

Iteratively printing an Object Arraystatic void print (Object[] objArray) {

System.out.print("{");for (int index = 0; index < objArray.length; index++) {

System.out.print(objArray[index]);if (index < objArray.length -1) System.out.print(", ");

}System.out.print ("}");

}

print (introProg); {14, Intro. Prog., COMP}

static Object[] introProg = {new Integer(14), "Intro. Prog.", "COMP"};

static Object[] foundProg = {new Integer(114), "Found. Prog.", "COMP"};

static Object[] programming = {introProg, foundProg};

print (programming); {[Ljava.lang.Object;@3f5d07, [Ljava.lang.Object;@f4a24a}

Problem

• One level loop single-level arrays

• Loop nested in loop array nested in array

• N-level loop N-level array

• What if N is not known at programming writing time?

• Loop nesting level fixed at program writing time.

Unknown N

print (introProg); {14, Intro. Prog., COMP}

static Object[] introProg = {new Integer(14), "Intro. Prog.", "COMP"};

static Object[] foundProg = {new Integer(114), "Found. Prog.", "COMP"};

static Object[] programming = {introProg, foundProg};

print (programming); {{14, Intro. Prog., COMP}, {114, Found. Prog., COMP}}

static Object[] algorithms = {new Integer(122), "Algorithms", "COMP"};

static Object[] compAnimation = {"Comp. Animation", "COMP"};

static Object[] otherCompSci = {algorithms, compAnimation};

static Object[] compSci = {programming, otherCompSci};

print (compSci) {{{14, Intro. Prog., COMP}, {114, Found. Prog., COMP}}, {{122, Algorithms, COMP}, {Comp. Animation, COMP}}}

Iteratively printing an Object Arraystatic void print (Object[] objArray) {

System.out.print("{");for (int index = 0; index < objArray.length; index++) {

System.out.print(objArray[index]);if (index < objArray.length -1) System.out.print(", ");

}System.out.print ("}");

}

Recursively printing an Object Array (edit)

static void print (Object[] objArray) {

System.out.print("{");

for (int index = 0; index < objArray.length; index++) {

Object element = objArray[index];

System.out.print(objArray[index]);

if (index < objArray.length -1) System.out.print(", ");

}

System.out.print ("}");

}

Recursively printing an Object Array (edited)

static void print (Object[] objArray) {

System.out.print("{");

for (int index = 0; index < objArray.length; index++) {

Object element = objArray[index];

if (isArray(element))

print((Object[])element);

else

System.out.print(objArray[index]);

if (index < objArray.length -1) System.out.print(", ");

}

System.out.print ("}");

}

Recursively printing an Object Arraystatic void print (Object[] objArray) {

System.out.print("{");for (int index = 0; index < objArray.length; index++) {

Object element = objArray[index];if (element.getClass().isArray())

print ((Object[]) element);else

System.out.print(objArray[index]);if (index < objArray.length -1)

System.out.print(", ");}System.out.print ("}");

}

iterationrecursion

Trees– Items (called nodes) connected by directed arrows

– Arrows describe parent child relationships– Source item called parent of destination

item– A node can be both a parent and a child– Single root item

• item with no parent

– Many leaf items• Items with no chidren

– Composite/internal node• Non-leaf node

– Subtree • Node and all of its descendents

– Component• Node with a parent -• All nodes except root

– Height of subtree• Number of nodes to leaf node along

longest path

– Level• Number of nodes to root node along unique

path to it.

C

D E

F

B

A

parent

children

root

G

H

Leaf item

subtree

Composite

Component

Height: 1

Height: 3

Height: 0

Trees

C

D E

F

B

A

parent

children

root

G

H

height: 1

height: 3

height: 0

leaf item

level: 0

level: 1

level: 2

Trees

C

D E

F

B

A

G

H

subtree

composite

component

Object Arrays and Treesstatic Object[] introProg = {new Integer(14), "Intro. Prog.", "COMP"};

static Object[] foundProg = {new Integer(114), "Found. Prog.", "COMP"};

static Object[] programming = {introProg, foundProg};

static Object[] algorithms = {new Integer(122), "Algorithms", "COMP"};

static Object[] compAnimation = {"Comp. Animation", "COMP"};

static Object[] otherCompSci = {algorithms, compAnimation};

static Object[] compSci = {programming, otherCompSci};

new Integer(14)

Intro Prog

COMP

introProg

programming

new Integer(114)

Found. Prog

COMP

foundProg

new Integer(122)

Algorithms

COMP

compSci

algorithms

COMPComp. Animation

compAnimation

otherCompSci

Tree-based Recursion

• Method gets some tree item as argument• Processes node.

– Leaf and non-leaf processing can be different

• Recursion occurs on children• Recursion ends when leaf node reached

Tree-based Recursion• Function gets some tree

item as argument• Processes node.

– Leaf and non-leaf processing can be different

• Recursion occurs on children

• Recursion ends when leaf node reached

static void print (Object[] objArray) {System.out.print("{");for (int index = 0; index < objArray.length; index++) {

Object element = objArray[index];if (element.getClass().isArray()) print ((Object[]) element);else System.out.print(objArray[index]);

if (index < objArray.length -1) System.out.print(", ");}

System.out.print ("}");}

Tree-based Recursionstatic void print (Object[] objArray) {

System.out.print("{");for (int index = 0; index < objArray.length; index++) {

Object element = objArray[index];if (element.getClass().isArray()) print ((Object[]) element);else

System.out.print(objArray[index]); if (index < objArray.length -1)

System.out.print(", ");}System.out.print ("}");

}

new Integer(14)

Intro Prog

COMP

introProg

programming

new Integer(114)

Found. Prog

COMP

foundProg

new Integer(122)

Algorithms

COMP

compSci

algorithms

COMPComp. Animation

compAnimation

otherCompSci

print (compSci)print (programming)

print (introProg){

{

{14, Intro Prog, COMP}

print (foundProg){114, Found. Prog., COMP}

}

print (otherCompSci) { }

print (algorithms){122, Algorithms, COMP}

print (compAnimation){Comp. Animation., COMP}

},

,

,

Loop to process nodes at same level

Recursion to go down a level

Pure Recursive Solution

• List-based recursion to process nodes at same level.

• Tree-based recursion to process nodes at the next level.

• Two different methods.

Pure recursive soln (edit)static void print (Object[] objArray) {

print (objArray, 0);}

static void print (Object[] objArray, int elementNo) {System.out.print("{");for (int index = 0; index < objArray.length; index++) {

Object element = objArray[index];System.out.print(objArray[index]);

if (index < objArray.length -1)System.out.print(", ");

}System.out.print ("}");

}

Pure recursive soln (edited)static void print (Object[] objArray) {

print (objArray, 0);}

static void print (Object[] objArray, int elementNo) {System.out.print("{");for (int index = 0; index < objArray.length; index++) {

Object element = objArray[index];System.out.print(objArray[index]);

if (index < objArray.length -1)System.out.print(", ");

}System.out.print ("}");

}

Pure Recursive Solution

static void print (Object[] objArray, int elementNo) {if (elementNo >= objArray.length)

return;else {

Object element = objArray[elementNo];if (element.getClass().isArray())

print ((Object[]) element);else

System.out.print(objArray[elementNo]);if (elementNo < objArray.length -1)

System.out.print(", ");print (objArray, elementNo + 1);

}}

static void print (Object[] objArray) {

System.out.print("{");

print (objArray, 0);

System.out.print ("}");

}

}

Direct recursion

Indirect recursion

List-based

Tree-based

Course problem solved so far• Given course information stored in flat course list

• Given a course, find the dept and number.

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new AFreshmanSeminar (“Lego Robots”,

“COMP” )

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

new AFreshmanSeminar (“Comp. Animation”,

“COMP” )

courses

Course problem solved so far

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new AFreshmanSeminar (“Lego Robots”,

“COMP” )

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

new AFreshmanSeminar (“Comp. Animation”,

“COMP” )

courses

static void fillCourses() { courses.addElement(new ARegularCourse ("Intro. Prog.", "COMP", 14)); courses.addElement(new ARegularCourse ("Found. of Prog.", "COMP", 114)); courses.addElement(new AFreshmanSeminar("Comp. Animation", "COMP")); courses.addElement(new AFreshmanSeminar("Lego Robots", "COMP"));}

Course Tree• Course information stored in hierarchical course lists.

• Leaf nodes are courses

• Given a course name, return leaf node matching title.

prog

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new AFreshmanSeminar (“Lego Robots”,

“COMP” )

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

new AFreshmanSeminar (“Comp. Animation”,

“COMP” )

courses

Course List Tree

prog

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new AFreshmanSeminar (“Lego Robots”,

“COMP” )

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

new AFreshmanSeminar (“Comp. Animation”,

“COMP” )

courses

static void fillCourses() { CourseList prog = new ACourseList(); prog.addElement(new ARegularCourse ("Intro. Prog.", "COMP", 14)); prog.addElement(new ARegularCourse ("Found. of Prog.", "COMP", 114)); courses.addElement(prog); courses.addElement(new AFreshmanSeminar("Comp. Animation", "COMP")); courses.addElement(new AFreshmanSeminar("Lego Robots", "COMP"));}

Why trees instead of flat lists• Information may come in hierarchical form

from organizations– programming group submits courses to CS

dept.– CS dept submits courses to arts and sciences– arts and sciences submits courses to UNC

• Can answer hierarchical queries– print all CS courses– print all programming courses– will not show benefit in example

Using Flat vs. Hierarchical Course Lists

static void fillCourses() { courses.addElement(new ARegularCourse ("Intro. Prog.", "COMP", 14)); courses.addElement(new ARegularCourse ("Found. of Prog.", "COMP", 114)); courses.addElement(new AFreshmanSeminar("Comp. Animation", "COMP")); courses.addElement(new AFreshmanSeminar("Lego Robots", "COMP"));}

static void fillCourses() { CourseList prog = new ACourseList(); prog.addElement(new ARegularCourse ("Intro. Prog.", "COMP", 14)); prog.addElement(new ARegularCourse ("Found. of Prog.", "COMP", 114)); courses.addElement(prog); courses.addElement(new AFreshmanSeminar("Comp. Animation", "COMP")); courses.addElement(new AFreshmanSeminar("Lego Robots", "COMP"));}

CourseList Course

Original Course and Course Listpackage courses;public interface Course {

public String getTitle();public String getDepartment();public int getNumber();public void init (String theTitle, String the Dept);

}

package collections;import courses.Course;public interface CourseList {

public void addElement(Course element);public int size();public Course elementAt(int index);public Course matchTitle (String theTitle);

}

package courseTree;public interface CourseList {

public void addElement(??? element);public int size();public Course elementAt(int index);public Course matchTitle (String theTitle);

}

Tree Course and Course Listpackage courseTree;public interface Course {

public String getTitle();public String getDepartment();public int getNumber();public void init (String theTitle, String the Dept);

}

package courses;public interface Course {

public String getTitle();public String getDepartment();public int getNumber();public void init (String theTitle, String the Dept);

}

package collections;public interface CourseList {

public void addElement(Object element);public int size();public Course elementAt(int index);public Course matchTitle (String theTitle);

}

Tree Course and Course List

Can put a BMISpreadsheet in it!

package courses;public interface Course {

public String getTitle();public String getDepartment();public int getNumber();public void init (String theTitle, String the Dept);

}

package collections;public interface CourseList {

public void addElement(TreeNode element);public int size();public Course elementAt(int index);public Course matchTitle (String theTitle);

}

Tree Course and Course List

package courses;public interface Course extends TreeNode {

public String getTitle();public String getDepartment();public int getNumber();public void init (String theTitle, String the Dept);

}

package collections;public interface CourseList extends TreeNode {

public void addElement(TreeNode element);public int size();public Course elementAt(int index);public Course matchTitle (String theTitle);

}

Tree Course and Course List

package courses;public interface Course extends TreeNode {

public String getTitle();public String getDepartment();public int getNumber();public void init (String theTitle, String the Dept);

}

package collections;public interface CourseList extends TreeNode {

public void addElement(TreeNode element);public int size();public Course elementAt(int index);public Course matchTitle (String theTitle);

}

Tree Course and Course List

Can add Course

Can add CourseList

Tree Node

package courseTree;public interface TreeNode {}

Empty for now.

Will fill it based on course list operations.

Tree Course and Course List

package courseTree;public interface CourseList extends TreeNode {

public void addElement(TreeNode element);public int size();public Course elementAt(int index);public Course matchTitle (String theTitle);

}

Only operation requiring re-implementation

matchTitle in flat list

Course[] contents = new Course[MAX_SIZE];

public Course matchTitle (String theTitle) { for (int courseIndex = 0; courseIndex < size; courseIndex++) {

if (contents[courseIndex].getTitle().equals(theTitle))return contents[courseIndex];

}return null;

}

matchTitle in hierarchical list? (edit)

Course[] contents = new Course[MAX_SIZE];

public Course matchTitle (String theTitle) { for (int courseIndex = 0; courseIndex < size; courseIndex++) {

if (contents[courseIndex].getTitle().equals(theTitle))return contents[courseIndex];

}return null;

}

matchTitle in hierarchical list? (edited)

TreeNode[] contents = new Course[MAX_SIZE];

public Course matchTitle (String theTitle) { for (int courseIndex = 0; courseIndex < size; courseIndex++) {

TreeNode element = contents[courseIndex];if (element instanceof Course) {

if (((Course)element).getTitle().equals(theTitle))return (Course) element;

} } else

return ((CourseList) element).matchTitle(theTitle);}

return null;}

matchTitle in hierarchical list? (edited)

TreeNode[] contents = new Course[MAX_SIZE];

public Course matchTitle (String theTitle) { for (int courseIndex = 0; courseIndex < size; courseIndex++) {

TreeNode element = contents[courseIndex];if (element instanceof Course) {

if (((Course)element).getTitle().equals(theTitle))return (Course) element;

} else { // instance of CourseList Course course = ((CourseList)

element).matchTitle(theTitle); if (course != null) return course;

}}

return null;}

matchTitle in hierarchical list? (edited)

TreeNode[] contents = new Course[MAX_SIZE];

public Course matchTitle (String theTitle) { for (int courseIndex = 0; courseIndex < size; courseIndex++) {

TreeNode element = contents[courseIndex];Course course = element.matchTitle(theTitle);if (course != null) return course;

} return null;}

matchTitle in hierarchical list

TreeNode[] contents = new TreeNode[MAX_SIZE];

public Course matchTitle (String theTitle) { for (int courseIndex = 0; courseIndex < size; courseIndex++) {

Course course = contents[courseIndex].matchTitle(theTitle);if ( course != null) return course;

} return null;}

matchTitle in ACourse

package courseTree;public abstract class ACourse implements Course { public Course matchTitle(String theTitle) {

if ( title.equals(theTitle))return this;

elsereturn null;

} …}

Final Tree Node

package courseTree;public interface TreeNode {

public Course matchTitle (String theTitle);}

Tracing matchTitle

prog

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new AFreshmanSeminar (“Lego Robots”,

“COMP” )

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

new AFreshmanSeminar (“Comp. Animation”,

“COMP” )

courses

matchTitle courses

function object result

matchTitle courses.contents[0]

matchTitle courses.contents[0].contents[0]

arg

“Comp. Animation”

“Comp. Animation”

“Comp. Animation”

Same implementation on two different objects

Arg does not get smaller

object doesDifferent dynamically dispatched implementations

Tracing matchTitle

prog

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new AFreshmanSeminar (“Lego Robots”,

“COMP” )

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

new AFreshmanSeminar (“Comp. Animation”,

“COMP” )

courses

matchTitle courses

function object result

matchTitle courses.contents[0]

matchTitle courses.contents[0].contents[0]

arg

“Comp. Animation”

null

“Comp. Animation”

“Comp. Animation”

Tracing matchTitle

prog

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new AFreshmanSeminar (“Lego Robots”,

“COMP” )

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

new AFreshmanSeminar (“Comp. Animation”,

“COMP” )

courses

matchTitle courses

function object result

matchTitle courses.contents[0]

arg

“Comp. Animation”

“Comp. Animation”

Tracing matchTitle

prog

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new AFreshmanSeminar (“Lego Robots”,

“COMP” )

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

new AFreshmanSeminar (“Comp. Animation”,

“COMP” )

courses

matchTitle courses

function object result

matchTitle courses.contents[0]

matchTitle courses.contents[0].contents[1]

arg

“Comp. Animation”

null

“Comp. Animation”

“Comp. Animation”

Tracing matchTitle

prog

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new AFreshmanSeminar (“Lego Robots”,

“COMP” )

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

new AFreshmanSeminar (“Comp. Animation”,

“COMP” )

courses

matchTitle courses

function object result

matchTitle courses.contents[0]

arg

“Comp. Animation”

“Comp. Animation” null

Tracing matchTitle

prog

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new AFreshmanSeminar (“Lego Robots”,

“COMP” )

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

new AFreshmanSeminar (“Comp. Animation”,

“COMP” )

courses

matchTitle courses

function object resultarg

“Comp. Animation”

Tracing matchTitle

prog

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new AFreshmanSeminar (“Lego Robots”,

“COMP” )

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

new AFreshmanSeminar (“Comp. Animation”,

“COMP” )

courses

matchTitle courses

function object result

matchTitle courses.contents[1]

arg

“Comp. Animation”

“Comp. Animation” courses.contents[1]

Tracing matchTitle

prog

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new AFreshmanSeminar (“Lego Robots”,

“COMP” )

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

new AFreshmanSeminar (“Comp. Animation”,

“COMP” )

courses

matchTitle courses

function object resultarg

“Comp. Animation” courses.contents[1]

Recursively visiting a tree

prog

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new AFreshmanSeminar (“Lego Robots”,

“COMP” )

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

new AFreshmanSeminar (“Comp. Animation”,

“COMP” )

courses

Recursively visiting a tree

prog

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new AFreshmanSeminar (“Lego Robots”,

“COMP” )

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

new AFreshmanSeminar (“Comp. Animation”,

“COMP” )

courses

Recursively visiting a tree

prog

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new AFreshmanSeminar (“Lego Robots”,

“COMP” )

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

new AFreshmanSeminar (“Comp. Animation”,

“COMP” )

courses

Recursively visiting a tree

prog

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new AFreshmanSeminar (“Lego Robots”,

“COMP” )

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

new AFreshmanSeminar (“Comp. Animation”,

“COMP” )

courses

Recursively visiting a tree

prog

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new AFreshmanSeminar (“Lego Robots”,

“COMP” )

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

new AFreshmanSeminar (“Comp. Animation”,

“COMP” )

courses

Recursively visiting a tree

prog

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new AFreshmanSeminar (“Lego Robots”,

“COMP” )

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

new AFreshmanSeminar (“Comp. Animation”,

“COMP” )

courses

Recursively visiting a tree

prog

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new AFreshmanSeminar (“Lego Robots”,

“COMP” )

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

new AFreshmanSeminar (“Comp. Animation”,

“COMP” )

courses

Recursively visiting a tree

prog

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new AFreshmanSeminar (“Lego Robots”,

“COMP” )

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

new AFreshmanSeminar (“Comp. Animation”,

“COMP” )

courses

Recursively visiting a tree

prog

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new AFreshmanSeminar (“Lego Robots”,

“COMP” )

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

new AFreshmanSeminar (“Comp. Animation”,

“COMP” )

courses

Recursively Visiting vs. Creating Tree• Visited (traversed) tree recursively

– matchTitle()

• So far, created fixed-size tree– Non-recursively

• Creating variable-size tree?– Must be done recursively as no of levels unknown

Problem

CourseList

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new AFreshmanSeminar (“Lego Robots”,

“COMP” )

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

new AFreshmanSeminar (“Comp. Animation”,

“COMP” )

CourseList

new Integer(14)

Intro Prog

COMP

Object[]

Object[]

new Integer(114)

Found. Prog

COMP

Object[]

Object[]

COMPComp. Animation

Object[]

COMPComp. Animation

Object[]

• From a course array tree, create a course list hierarchy

CourseList

new Integer(14)

Intro Prog

COMP

Object[]

Object[]

new Integer(114)

Found. Prog

COMP

Object[]

Object[]

COMPComp. Animation

Object[]

COMPComp. Animation

Object[]

static CourseList courseArrayToCourseList (Object[] courseArray)

CourseList

CourseList

new Integer(14)

Intro Prog

COMP

Object[]

Object[]

new Integer(114)

Found. Prog

COMP

Object[]

Object[]

COMPComp. Animation

Object[]

COMPComp. Animation

Object[]

static CourseList courseArrayToCourseList (Object[] courseArray)

CourseList

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

CourseList

new Integer(14)

Intro Prog

COMP

Object[]

Object[]

new Integer(114)

Found. Prog

COMP

Object[]

Object[]

COMPComp. Animation

Object[]

COMPComp. Animation

Object[]

static CourseList courseArrayToCourseList (Object[] courseArray)

CourseList

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

CourseList

new Integer(14)

Intro Prog

COMP

Object[]

Object[]

new Integer(114)

Found. Prog

COMP

Object[]

Object[]

COMPComp. Animation

Object[]

COMPComp. Animation

Object[]

static CourseList courseArrayToCourseList (Object[] courseArray)

CourseList

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

CourseList

new Integer(14)

Intro Prog

COMP

Object[]

Object[]

new Integer(114)

Found. Prog

COMP

Object[]

Object[]

COMPComp. Animation

Object[]

COMPComp. Animation

Object[]

static CourseList courseArrayToCourseList (Object[] courseArray)

CourseList

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

CourseList

new Integer(14)

Intro Prog

COMP

Object[]

Object[]

new Integer(114)

Found. Prog

COMP

Object[]

Object[]

COMPComp. Animation

Object[]

COMPComp. Animation

Object[]

static CourseList courseArrayToCourseList (Object[] courseArray)

CourseList

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

CourseList

new Integer(14)

Intro Prog

COMP

Object[]

Object[]

new Integer(114)

Found. Prog

COMP

Object[]

Object[]

COMPComp. Animation

Object[]

COMPComp. Animation

Object[]

static CourseList courseArrayToCourseList (Object[] courseArray)

CourseList

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

new AFreshmanSeminar (“Comp. Animation”,

“COMP” )

CourseList

new Integer(14)

Intro Prog

COMP

Object[]

Object[]

new Integer(114)

Found. Prog

COMP

Object[]

Object[]

COMPComp. Animation

Object[]

COMPComp. Animation

Object[]

static CourseList courseArrayToCourseList (Object[] courseArray)

CourseList

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

new AFreshmanSeminar (“Comp. Animation”,

“COMP” )

CourseList

new Integer(14)

Intro Prog

COMP

Object[]

Object[]

new Integer(114)

Found. Prog

COMP

Object[]

Object[]

COMPComp. Animation

Object[]

COMPComp. Animation

Object[]

static CourseList courseArrayToCourseList (Object[] courseArray)

CourseList

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new AFreshmanSeminar (“Lego Robots”,

“COMP” )

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

new AFreshmanSeminar (“Comp. Animation”,

“COMP” )

CourseList

new Integer(14)

Intro Prog

COMP

Object[]

Object[]

new Integer(114)

Found. Prog

COMP

Object[]

Object[]

COMPComp. Animation

Object[]

COMPComp. Animation

Object[]

static CourseList courseArrayToCourseList (Object[] courseArray)

CourseList

new ARegularCourse (“Intro. Prog”, “COMP” , 14)

new AFreshmanSeminar (“Lego Robots”,

“COMP” )

new ARegularCourse (“Found. Prog.”, “COMP” , 114)

new AFreshmanSeminar (“Comp. Animation”,

“COMP” )

CourseList

new Integer(14)

Intro Prog

COMP

Object[]

Object[]

new Integer(114)

Found. Prog

COMP

Object[]

Object[]

COMPComp. Animation

Object[]

COMPComp. Animation

Object[]

static CourseList courseArrayToCourseList (Object[] courseArray)

Helper methods

static boolean isFreshmanSeminar (Object[] courseArray) {if (courseArray.length != 2) return false;if (courseArray[0] instanceof String) return true;else return false;

}

static boolean isRegularCourse (Object[] courseArray) {if (courseArray.length != 3) return false;if (courseArray[0] instanceof Integer) return true;else return false;

}

static Course courseArrayToRegularCourse (Object[] courseArray) { return (new ARegularCourse ((String) courseArray[1], (String) courseArray[2],

((Integer) courseArray[0]).intValue()));}

static FreshmanSeminar courseArrayToFreshmanSeminar (Object[] courseArray) { return (new AFreshmanSeminar((String) courseArray[0], (String) courseArray[1]));}

static CourseList courseArrayToCourseList (Object[] courseArray) (edit)

// gets an array representing a set of courses rather than an individual coursestatic CourseList courseArrayToCourseList (Object[] courseArray) { }

static CourseList courseArrayToCourseList (Object[] courseArray) (edited)

// gets an array representing a set of courses rather than an individual coursestatic CourseList courseArrayToCourseList (Object[] courseArray) { if (isFreshmanSeminar(courseArray)) return courseArrayToFreshmanSeminar(courseArray); else (ifRegularCourse(courseArray)) return courseArrayToRegularCourse(courseArray); else { CourseList courseList = new ACourseList(); for (int index =0; index < courseArray.length; index++) courseList.addElement( courseArrayToCourseList(courseArray[index]));

return courseList; } }

static CourseList courseArrayToCourseList (Object[] courseArray)

// gets an array representing a set of courses rather than an individual coursestatic CourseList courseArrayToCourseList (Object[] courseArray) { CourseList courseList = new ACourseList(); for (int index = 0; index < courseArray.length; index++) { Object[] element = (Object[]) courseArray[index]; if (isFreshmanSeminar(element))courseList.addElement(courseArrayToFreshmanSeminar(element)); else if (isRegularCourse(element))courseList.addElement(courseArrayToRegularCourse(element)); elsecourseList.addElement(courseArrayToCourseList(element)); } return courseList;}

Composite design pattern

package courseTree;public interface TreeNode { public Course matchTitle (String theTitle);}

package courseTree;public interface Course extends TreeNode { public String getTitle(); public String getDepartment(); public int getNumber();}

package courseTree;public interface CourseList extends TreeNode { public void addElement(TreeNode element); public int size(); public Course elementAt(int index);}

Common tree node interface

Additional composite methodsAdditional leaf methods

Composite design pattern

TreeNode

Leaf Composite

Common tree node interface

Additional composite methods

Additional leaf methods

Composite design pattern with no special leaf methods

TreeNode

Composite

Composite design pattern with no special composite methods

TreeNode

Leaf

Composite design pattern with no special leaf or composite methods

TreeNode

Composite design pattern with multiple leaf/composite types

TreeNode

Leaf1 Composite1Leaf2 Composite2

Composite design pattern with leaf/component hierarchies

TreeNode

Leaf Composite

Leaf1 Composite1Leaf2 Composite2

Composite design pattern with interfaces

TreeNode

Leaf Composite

Common tree node interface

Additional composite methods

Additional leaf methods

extendsextends

Composite design pattern with interfaces and classes

TreeNode

ALeaf AComposite

Common tree node interface

Additional composite methods

Additional leaf methods

implements implements

LeafOnly CompositeOnly

Composite design pattern with classes only

ATreeNode

ALeaf AComposite

Common abstract class

extends extends

Additional composite methods

Additional leaf methods

Hierarchical Window Tree

frame

Panel Panel

TextField ButtonTextField Button

Container

Component

AWT Classes

Component

Container TextField

PanelFrame

Button

TreeNode MethodsGeneral

CompositeMethods

Specialized Composite Methods

Specialized Leaf Methods

Creating Window Structure

frame

Panel Panel

TextField ButtonTextField Button

Frame frame = new Frame("Points Plotter");

Panel control = new Panel();

frame.add( new Panel());

control.add( new Button(“New Point”));

control.add(new Button(“Quit”);

control.add(new TextField(“0”));

frame.add(control);

control.add(new TextField(“0”)); Like creating hierarchical course lists in fillCourses

Add() definition?

• public void add (T element)

• T?– Component

• Class in which method defined?– Container

• Can we add containers to containers?– Container Is-A component

Leaf-specific methods

• TextField– getText(), setText()

• Cannot invoke them on buttons or containers.

TreeNode methods

• Defined in component– paint()

• Each concrete class implements it in its own way• A container class just calls paint() on its

components.• Does not have to worry about how to implement it.• Don’t have to change a container class as new

components are implemented.• No instanceof operation!

Grammars• Noun Phrases

– boy

– little boy– smart little boy– naughty smart little boy

• Structure decompositions formally described by grammar rules– <Noun Phrase> <Noun>– <Noun Phrase>

<Adjective> <Noun Phrase>• Words within angle brackets

called non-terminals– think of them as types

• There may be multiple rules describing a non-terminal

• Rules describe valid sequences of terminals– naughty smart little boy– Think of them as type instances

<Noun Phrase>

boy

<Adjective> <Noun Phrase>

boy

<Noun>

little boy

little

Smart little boy

<Adjective>

smart

Recursive definition

<Noun Phrase>

Describing list-based tail recursion with grammars

• Recursive function decomposes a list into items using the following grammar:– <List> <Item> <List>– <List> empty

<List>

<Item>

6

[ 6 5]

<List>

<Item>

5

[ 6]

<List>

empty

[]

Printing an Enumeration – Recursive Solution

static void print (StringEnumeration stringEnumeration) {if (!stringEnumeration.hasMoreElements()) return;else {

System.out.println(stringEnumeration.nextElement());print (stringEnumeration);

}}

<List> empty

<List> <Item> <List>

Describing Iteration with Kleene *

• Iterative solution described using Kleene *– <List> <Item> *

<Item>

5

<List>

<Item>

6

[ 6 5]

Printing an Enumeration – Iterative Solution

static void print(StringHistory strings) {System.out.println("******************");StringEnumeration stringEnumeration = strings.elements();while (stringEnumeration.hasMoreElements()) {

System.out.println(stringEnumeration.nextElement());}System.out.println("******************");

}

<List> <Item> *

Object vs. Call Structure• In both cases object is same

– Flat list

• Structure of method calls is different– Grammar describes tree of

method calls

• Why grammar?– Sometimes given

• E.g. programming language or expressions

– As a high-level step before method coded

<List>

<Item>

5

<List>

<Item>

6

[ 6 5]

empty

5

<List>

<Item>

6

[ 6 5]

Describing tree recursion with grammars

• Hybrid recursive and iterative decomposition– <TreeNode> <TreeNode >*– <TreeNode> <Item>

[]

<TreeNode>

<Item>

6

[[3 4 ] 6 []]

<TreeNode>

<TreeNode>

3

<Item>

4

<TreeNode>

<Item>

<TreeNode> <TreeNode>

Recursively printing an Object Arraystatic void print (Object[] objArray) {

System.out.print("{");for (int index = 0; index < objArray.length; index++) {

Object element = objArray[index];if (element.getClass().isArray())

print ((Object[]) element);else

System.out.print(objArray[index]);if (index < objArray.length -1)

System.out.print(", ");}System.out.print ("}");

}

<TreeNode> <TreeNode >*

<TreeNode> <Item>

Grammar for pure tree recursion (edit)

• Hybrid recursive and iterative decomposition– <TreeNode> <TreeNode >*– <TreeNode> <Item>

Grammar for pure tree recursion (edited)

• Hybrid recursive and iterative decomposition– <TreeNode> <TreeNodeList >– <TreeNode> <Item>– <TreeNodeList> --> <TreeNode> <TreeNodeList>– <TreeNodeList> --> empty

Grammar for pure tree recursion• Pure recursive decomposition

– <TreeNode> <TreeNodeList>– <TreeNode> <Item>– <TreeNodeList> empty– <TreeNodeList> <TreeNode> <TreeNodeList>

<TreeNodeList>

[[3 4 ] 6 []]

<TreeNodeList>

4

<Item>

3<Item>

<TreeNode> <TreeNodeList>

<TreeNode> <TreeNodeList>

<TreeNode>

[]

<Item>

6

<TreeNode> <TreeNodeList>

<TreeNodeList>

Indirect recursion

<TreeNode> <TreeNodeList>

empty

Direct recursion

<TreeNode> <TreeNodeList>

empty

• Pure recursive decomposition– <TreeNode> <TreeNode List>– <TreeNode> <Item>– <Tree Node List> empty– <Tree Node List> <Tree Node> <Tree Node

List>

Pure Recursive Solution

static void print (Object[] objArray, int elementNo) {if (elementNo >= objArray.length)

return;else {

Object element = objArray[elementNo];if (element.getClass().isArray())

print ((Object[]) element);else

System.out.print(objArray[elementNo]);if (elementNo < objArray.length -1)

System.out.print(", ");print (objArray, elementNo + 1);

}}

static void print (Object[] objArray) {

System.out.print("{");

print (objArray, 0);

System.out.print ("}");

}

}

Structure of object vs. structure of method

• In both previous cases object is same– Flat list

• Structure of method calls is different– Grammar describes tree of method calls

• Why grammar?– Sometimes given

• E.g. programming language or expressions

– As a high-level step before method coded

Grammar for simple expression (edit)

5 + 4 * 3

Grammar for simple expression (edited)

5 + 4 * 3

<Expression> -> <Number>

<Expression> <Number> <Operator> <Expression>

Grammar for simple expression

5 + 4 * 3

<Expression> <Number>

<Expression> <Number> <Operator> <Expression>

<Expression>

+5

<Operator><Number> <Expression>

<Number>

4 *

<Operator> <Expression>

5

<Number>

Iterative vs. Recursive Solution

• Previous grammar can be used for recursive evaluation of flat lists– Extra credit to do it

• Grammar used for loop-based solution– <Expression> <Token> *

Grammar for nested expression (edit)

5 + (4 * (3/2))

<Expression> <Number>

<Expression> <Number> <Operator> <Expression>

Grammar for nested expression (edited)

5 + () + (4 * (3/2))

<Expression> <Number>

<Expression> <Number> <Operator> <Expression>

<Expression> -> (<Expression>)

Grammar for nested expression5 + (4 * (3/2))<Expression> <Number><Expression> <Number> <Operator> <Expression><Expression> ( <Expression>)

Terminal (matches itself only)

More on grammars

• From a theoretical point of view– Theory of computation (COMP 181)

• From a practical point of view– Compilers (COMP 140)

• Both are optional– Please take them!