Title: Chapter 19 : Recursion
1Chapter 19 Recursion
2Iterative Algorithms
- Algorithm
- Specifies a step in the solution process.
- Step is iterated.
- After each iteration, we are closer to solution.
- Solution is reached after a finite number of
iterations.
3Recursion
- Algorithms
- Solve a trivial, basic case of problem,
- Solution to general case is reduced to one that
is a step closer to basic case.
4Iteration v.s. Recursion
- Reducing general case to a easier case roughly
corresponds to a single iterative step. - Reaching base case stops recursion as exit
condition stops iteration.
5Iteration v.s. Recursion
- In an iterative solution
- step toward solution until while condition is
false. - explicitly drive repetition with a loop.
- In a recursive solution,
- reduce or unwind problem until base case.
- write a solution for base case and for reduction
step.
6Recursive solution form
- if ( trivial case )
- solve directly
- else
- solve in terms of a slightly easier case
7Sorting a list
- Trivial case
- size of list is one or zero.
- General case
- Size of list is greater than 1.
- Slightly easier problem
- reduce general case to sort a list with one fewer
element.
8Sorting a list
- if ( list is empty or has one element )
- solution is easy do nothing
- else
- sort the list, assuming a way of sorting a
listwith one fewer element is available
9Recursive algorithm implementation
- Trivial case
- Solved directly.
- General case
- algorithm invokes itself to solve a slightly
reduced case. - solution is built from solution of slightly
reduced case.
10Recursive algorithm execution
- Results in a chain of self-calls,
- each a slightly easier problem to solve that
previous. - Finally method is invoked with trivial case.
11Recursive algorithm correctness
- Must guarantee that general case will eventually
reduce to basic case.
12Example Exponentiation
- public static int power (int number, int
exponent) - The specified number raised to the specified
power. - require exponent gt 0
13Exponentiation iterative solution
public static int power (int number, int
exponent) int result 1 int count
0 while (count ! exponent) result number
result count count 1 return
result
- Invariant result equals number raised to the
count power. - Exponent requirement to be gt 0 ensures iteration
will terminate.
14Exponentiation recursive solution
- Base cases raise integer to the power 0.
- General case raise integer to the power n, n is
an integer and n gt 0. - Reduction step raising a number to the power
n-1.
15Exponentiation recursive solution
- Compute number to the power n, assuming we have
already computed number to the power n-1. - If we have numbern-1,
- multiply this value by number to get numbern.
- number n-1 is gotten by a self-call
- power (number, n-1)
16Exponentiation recursive solution
- /
- The specified number raised to the specified
power. - require exponent gt 0
- /
- public static int power (int number, int
exponent) - int result
- if (exponent 0)
- result 1
- else
- result number power(number,exponent-1)
- return result
17Tracing recursion invoking power(2,3)
if (exponent 0) result 1 else result
number power(number,exponent-1) return
result
number
2
3
exponent
result
18Tracing recursion invoking power(2,3)
if (exponent 0) result 1 else result
number power(number,exponent-1) return
result
number
2
3
exponent
result
19Tracing recursion invoking power(2,3)
if (exponent 0) result 1 else result
number power(number,exponent-1) return
result
invoke
number
2
3
exponent
result
20Tracing recursion invoking power(2,2)
if (exponent 0) result 1 else result
number power(number,exponent-1) return
result
number
2
2
exponent
result
21Tracing recursion invoking power(2,2)
if (exponent 0) result 1 else result
number power(number,exponent-1) return
result
invoke
number
2
2
exponent
result
22Tracing recursion invoking power(2,1)
if (exponent 0) result 1 else result
number power(number,exponent-1) return
result
number
2
1
exponent
result
23Tracing recursion invoking power(2,1)
if (exponent 0) result 1 else result
number power(number,exponent-1) return
result
number
2
1
exponent
result
24Tracing recursion invoking power(2,1)
if (exponent 0) result 1 else result
number power(number,exponent-1) return
result
invoke
number
2
1
exponent
result
25Tracing recursion invoking power(2,0)
if (exponent 0) result 1 else result
number power(number,exponent-1) return
result
number
2
0
exponent
result
26Tracing recursion invoking power(2,0)
if (exponent 0) result 1 else result
number power(number,exponent-1) return
result
number
2
0
exponent
result
1
27Tracing recursion invoking power(2,0)
if (exponent 0) result 1 else result
number power(number,exponent-1) return
result
number
2
0
exponent
result
1
28Tracing recursion invoking power(2,1)
if (exponent 0) result 1 else result
number power(number,exponent-1) return
result
Result of previous call
1
number
2
0
exponent
result
1
29Tracing recursion invoking power(2,1)
if (exponent 0) result 1 else result
number power(number,exponent-1) return
result
number
2
0
exponent
result
2
30Tracing recursion invoking power(2,1)
if (exponent 0) result 1 else result
number power(number,exponent-1) return
result
number
2
0
exponent
result
2
31Tracing recursion invoking power(2,2)
if (exponent 0) result 1 else result
number power(number,exponent-1) return
result
Result of previous call
2
number
2
0
exponent
result
2
32Tracing recursion invoking power(2,2)
if (exponent 0) result 1 else result
number power(number,exponent-1) return
result
number
2
0
exponent
result
4
33Tracing recursion invoking power(2,2)
if (exponent 0) result 1 else result
number power(number,exponent-1) return
result
number
2
0
exponent
result
4
34Tracing recursion invoking power(2,3)
if (exponent 0) result 1 else result
number power(number,exponent-1) return
result
Result of previous call
4
number
2
0
exponent
result
4
35Tracing recursion invoking power(2,3)
if (exponent 0) result 1 else result
number power(number,exponent-1) return
result
number
2
0
exponent
result
8
36Tracing recursion invoking power(2,3)
if (exponent 0) result 1 else result
number power(number,exponent-1) return
result
number
2
0
exponent
result
8
37Finding the minimum element Recursive version
- public int minFinalExam (ListltStudentgt students)
- The lowest final exam grades of the specified
Students. - require students.size() gt 0
38Finding the minimum element Recursive version
- Base case find smallest on list containing one
element. - General case find smallest on list with n
elements, where n gt 1. - Reducing general case find smallest on list with
n-1 elements.
39Finding the minimum element Recursive version
- how to find smallest of n elements, assuming we
know how to find smallest of n-1 elements. - Find smallest of the n-1 elements after first.
- Find smallest of this and the first.
40Finding the minimum element Recursive version
- private int minFinalExam (ListltStudentgt
students, int first) - Lowest final exam grades of Students on the list
with indexes greater than or equal to first. - require 0 lt first first lt students.size()
- public int minFinalExam (ListltStudentgt students)
- return minFinalExam(students,0)
41Finding the minimum element Recursive version
- private int minFinalExam (ListltStudentgt
students, int first) - int smallest
- int gradeOfFirst students.get(first).finalExam(
) - if (first students.size()-1)
- smallest gradeOfFirst // the base case
- else // the general case
- int minOfRest minFinalExam(students,first1)
- if (minOfRest lt gradeOfFirst)
- smallest minOfRest
- else
- smallest gradeOfFirst
-
- return smallest
42Selection sort recursive version
- Base cases sort an empty list or with 1 element.
- General case sort a list containing n elements,
n gt 1. - Reducing general case sort a list containing n-1
elements.
43Selection sort recursive version
- Find the smallest element and put it in first
place. - Sort the remaining n-1 elements.
- Note sorting the remaining n-1 elements, refers
to a segment of the list
first
remaining n-1 elements
44Selection sort recursive version
- private static ltElementgt void selectionSort
(ListltElementgt list, int first, OrderltElementgt
order) - if (first lt list.size())
- find the smallest element and put it first
- sort the remaining n-1 elements
-
45Selection sort recursive version
- private static ltElementgt void selectionSort
(ListltElementgt list, int first, OrderltElementgt
order) - if (first lt list.size())
- int small
- smallestOf(list,first,list.size()-1,order
) - interchange(list,first,small)
- selectionSort(list,first1,order)
-
46Selection sort recursive version
- public static ltElementgt void selectionSort
( ListltElementgt list, OrderltElementgt order) - selectionSort(list,0,order)
47Towers of Hanoi
- move stack of disks from starting peg to one of
the other pegs. Disks are moved one at a time,
and a disk can never be placed on top of a
smaller one.
48Example of moves with 3 discs
49Example of moves with 3 discs
50Example of moves with 3 discs
51Example of moves with 3 discs
52Example of moves with 3 discs
53Example of moves with 3 discs
54Example of moves with 3 discs
55Example of moves with 3 discs
56Example of moves with 3 discs
57Example of moves with 3 discs
58Example of moves with 3 discs
59Example of moves with 3 discs
60Example of moves with 3 discs
61Example of moves with 3 discs
62Example of moves with 3 discs
63PuzzleSolver method moveTower
- public void moveTower (int size, int from, int
to) - Move a tower of the specified number of disks
from the specified starting peg to the
specified destination peg. - require size gt 1 1 lt from from lt 3 1 lt
to to lt 3 from ! to
64PuzzleSolver method moveTower
- It uses a private method to move one disc
private void moveDisk (int from, int to) Move a
single disk from the specified peg to the
specified destination. require 1 lt from
from lt 3 1 lt to to lt 3 from ! to
65PuzzleSolver method moveTower
- Base case a tower with 1 disc.
- General case a tower with n discs.
- Reduction case move a tower with n-1 discs.
66PuzzleSolver method moveTower
- Reduce problem of moving n disks to problem of
moving n-1 - Move n-1 disks from starting peg to the other
peg. - Move a disk from starting peg to the destination
peg. - Move n-1 disks from other peg to the
destination peg. - To find other peg
- subtract source peg number (from) and destination
peg number (to) from 6 ( 1 2 3).
67PuzzleSolver moveTower implementation
- public void moveTower (int n, int from, int to)
- if (n 1)
- moveDisk(from,to)
- else
- int other 6-from-to // not from or to
- moveTower(n-1,from,other)
- moveDisk(from,to)
- moveTower(n-1,other,to)
-
68PuzzleSolver moveDisk
private void moveDisk (int from, int to)
System.out.println( "Move a disk from peg "
from " to peg " to '.')
69PuzzleSolver moveDisk
- Not very satisfactory.
- PuzzleSolver is a model class
- should be independent of the user interface.
70PuzzleSolver moveDisk
- Better way to implement moveDisk
- Use the Observer pattern.
- When output client is notified, pass move to make
public class Move A move in the Towers puzzle.
Pegs are numbered 1, 2, 3. public Move (int
from, int to) Create a move of a disk from the
peg from to the peg to. public int from
() Peg the disk is moved from. public int to
() Peg the disk is moved to.
71PuzzleSolver moveDisk
- private void moveDisk (int from, int to)
- setChanged()
- notifyObservers(new Move(from, to))
72Quicksort
- Quicksort
- puts an arbitrary element in proper position,
- smaller elements are below it.
- larger elements are above it.
- Sublists 2, 3 are recursively sorted.
73Quicksort
- Implement a private method to sort a list
segment. - sort calls method with entire list
public static ltElementgt void quickSort
( ListltElementgt list, OrderltElementgt order)
quickSort(list,0,list.size()-1,order) //Sor
t list elements indexed first through last. //
require 0 lt first last lt list.size() private
static ltElementgt void quickSort ( ListltElementgt
list, int first, int last, OrderltElementgt order)
74Quicksort
- Base case
- an empty list or a list with a single element.
- The general case is handled by the three steps
- puts an arbitrary element in proper position,
- smaller elements are below it.
- larger elements are above it.
- Sublists 2, 3 are sorted.
75Quicksort partition
- This method positions pivot such that
- Smaller elements in list are below it.
- Larger elements in list are above it.
- Reports where pivot was placed.
76Quicksort
- private static ltElementgt void quickSort
( ListltElementgt list, int first, int
last, OrderltElementgt order) - if (first lt last)
- int position // pivot index
- position partition(list,first,last,order)
- quickSort(list,first,position-1,order)
- quickSort(list,position1,last,order)
-
77Quicksort partition
- Choose middle element of sublist as pivot
element.
- move the pivot element into the last position
78Quicksort partition
pi
i
79Quicksort partition
- i, pi start at 0
- Compare i-th entry with pivot
pi
i
80Quicksort partition
- Compare i-th entry with pivot.
pi
i
81Quicksort partition
- Compare i-th entry with pivot.
pi
i
82Quicksort partition
- Compare i-th entry with pivot. Its less.
- Swap and increment indices.
pi
i
83Quicksort partition
- Compare i-th entry with pivot.
1
23
46
56
3
18
30
73
19
28
12
61
41
45
55
(5)
(6)
(8)
(7)
(9)
(10)
(11)
(13)
(12)
(14)
(0)
(1)
(3)
(2)
(4)
i
84Quicksort partition
- Compare i-th entry with pivot. Its less.
- Swap and increment indices.
1
23
46
56
3
18
30
73
19
28
12
61
41
45
55
(5)
(6)
(8)
(7)
(9)
(10)
(11)
(13)
(12)
(14)
(0)
(1)
(3)
(2)
(4)
85Quicksort partition
- Compare i-th entry with pivot.
23
46
56
3
18
30
73
19
28
12
61
1
45
55
41
(5)
(6)
(8)
(7)
(9)
(10)
(11)
(13)
(12)
(14)
(0)
(1)
(3)
(2)
(4)
86Quicksort partition
- Compare i-th entry with pivot.
23
46
56
3
18
30
73
19
28
12
61
1
45
55
41
(5)
(6)
(8)
(7)
(9)
(10)
(11)
(13)
(12)
(14)
(0)
(1)
(3)
(2)
(4)
87Quicksort partition
- Compare i-th entry with pivot. Its less.
- Swap and increment.
23
46
56
3
18
30
73
19
28
12
61
1
45
55
41
(5)
(6)
(8)
(7)
(9)
(10)
(11)
(13)
(12)
(14)
(0)
(1)
(3)
(2)
(4)
88Quicksort partition
- Compare i-th entry with pivot. Its less.
- Swap and increment indices.
45
46
56
3
18
30
73
19
28
12
61
1
23
55
41
(5)
(6)
(8)
(7)
(9)
(10)
(11)
(13)
(12)
(14)
(0)
(1)
(3)
(2)
(4)
89Quicksort partition
- Compare i-th entry with pivot. Its less.
- Swap and increment indices.
45
46
56
18
30
73
19
28
12
3
1
23
55
41
61
(5)
(6)
(8)
(7)
(9)
(10)
(11)
(13)
(12)
(14)
(0)
(1)
(3)
(2)
(4)
90Quicksort partition
- Compare i-th entry with pivot.
45
46
56
55
30
73
19
28
12
3
1
23
18
41
61
(5)
(6)
(8)
(7)
(9)
(10)
(11)
(13)
(12)
(14)
(0)
(1)
(3)
(2)
(4)
91Quicksort partition
- Compare i-th entry with pivot. Its less
- Swap and increment indices.
45
46
56
55
30
73
19
28
12
3
1
23
18
41
61
(5)
(6)
(8)
(7)
(9)
(10)
(11)
(13)
(12)
(14)
(0)
(1)
(3)
(2)
(4)
92Quicksort partition
- Compare i-th entry with pivot.
45
46
56
55
30
73
41
28
12
3
1
23
18
19
61
(5)
(6)
(8)
(7)
(9)
(10)
(11)
(13)
(12)
(14)
(0)
(1)
(3)
(2)
(4)
93Quicksort partition
- Loop exited. Swap pivot with pi.
45
46
56
55
30
73
41
28
12
3
1
23
18
19
61
(5)
(6)
(8)
(7)
(9)
(10)
(11)
(13)
(12)
(14)
(0)
(1)
(3)
(2)
(4)
94Quicksort partition
45
28
56
55
30
73
41
46
12
3
1
23
18
19
61
(5)
(6)
(8)
(7)
(9)
(10)
(11)
(13)
(12)
(14)
(0)
(1)
(3)
(2)
(4)
95partition implementation
private static ltElementgt int partition
(ListltElementgt list, int first, int last,
OrderltElementgt order) int pi // pivot
index int i // index of the next to
examine Element pivot // pivot item int mid
(firstlast)/2 pivot list.get(mid) interchan
ge(list,mid,last) // put pivot item at end. pi
first i first while (i ! last) //
list.get(last) is pivot item if
(order.inOrder(list.get(i),pivot))
interchange(list,pi,i) pi
pi1 i i1 interchange(list,pi,last)
// put pivot item in place return pi
96Indirect Recursion
- Method m1 invokes m2 which invokes m3 which
invokes mn which invokes m1.
97Indirect Recursion RemoveSet
- Given a balanced string of parentheses as
argument, removes the first balanced substring
from the front. - Examples
- removeSet("()") ? ""
- removeSet("()()()()") ? "()()()"
- removeSet("((()))") ? ""
- removeSet("(()()(()()))()(())") ? "()(())"
98RemoveSet design
- Remove first (
- Invoke reduceClosed for matching )
private String reduceClosed (String s) A String
equal to specified String with first substring
with one more closed parenthesis than open
parenthesis removed.
99RemoveSet design
- For example,
- reduceClosed(")") ? "
- reduceClosed(")()()") ? "()()
- reduceClosed("(()()))(()) ? "(())
- reduceClosed("()()(()()))()(())") ? "()(())"
100RemoveClosed design
- Basic case first character is ).
- General case first character of s is open
parenthesis then s starts with balanced
substring. - Remove balanced substring,
- Recursively apply method to whats left.
101RemoveClosed design
- Use removeSet to remove balanced substring
private String reduceClosed (String s) if
(head(s) ')') return tail(s) else //
head(s) '(, remove balanced set. return
reduceClosed(removeSet(s))
102Backtracking
- Algorithmic technique for solving problems that
cannot be solved directly. - Backtracking is used when a large set of possible
solutions must be examined to find an actual
solution to the problem.
103Backtracking
- For backtracking to be an appropriate technique,
problem solution must be - a composite, made up of parts
- constructible in a series of steps, with each
step adding a piece to the solution. - At each step there will several possible ways of
extending the partial solution of the previous
step. Some of these alternative will lead to a
solution, others will not.
104Backtracking example
- suppose we have a maze consisting of a set of
rooms connected by passages. - Each room is connected to one or more passages.
- A passage may lead to another room, or may lead
to the maze exit.
105Backtracking example
- For instance, a maze with seven rooms might look
like this, where the rooms are lettered and the
doors are labelled north, south, east, west.
106Backtracking example
- Problem find a path from a given room to the
exit. - Note solution is composite
- to reach the exit from room F, go south to room
D, west to room C, east to room E, east to the
exit. - The path can be constructed in a series of steps,
each step adding a component to the partial
solution built in the previous step.
107Backtracking example
- At each step, there may be several alternatives.
- For example, the first step in the above solution
is go south to room D. - This partial solution can be extended in two
ways go west to room C or go south to room
G. - The first option leads to a solution, while the
second does not. Room G is a dead end.
108Backtracking example
- Backtracking works by repeatedly extending a
partial solution until a solution is found or a
dead end is reached. - A dead end is simply a state that cannot be
further extended. - If a dead end is reached, the algorithm backs
up to the most recent point at which untried
possibilities exist, and tries one.
109Backtracking example
- To see how this works, suppose we are trying to
reach the exit from room A in the above maze. - room A
- go north to room B
- dead end back up to room A.
- go south to room C
- go north to room D
- go east to room F
- dead end back up to room D.
- go south to room G
- dead end back up to room D.
- no more choices (dead end) back up to room C
- go east to room E
- go east to exit.
110Implementing backtracking
- Implement a backtracking algorithm for the maze
traversal problem. - A Maze is composed of a number of Rooms, with
each Room connected to a number of other Rooms.
111Implementing backtracking
- public ListltRoomgt connections ()
- The list of Rooms this Room is connected to.
- public boolean isExit ()
- This Room is a maze exit.
112Implementing backtracking
- public class PathPoint
- A Room and a connection from the Room.
- public PathPoint (Room room, int connection)
- Create a new PathPoint.
- require 0ltconnection
- connection lt room.connections().size()
113Implementing backtracking
- A path is a list of PathPoints modeling a
sequence of connected Rooms. - If PathPoint B,j follows A,i on list, then
connection i from Room A leads to Room B. That
is, A.connections(i) B. - Require path has no repeated Rooms.
- A Path from Room A to H is (A,1),(C,2),(E,1)
114Implementing backtracking
- write a method that will produce an exit path
from a specified Room
public ListltPathPointgt exitPathFrom (Room room) A
path leading from the specified Room to an exit
returns null if no path exists.
- use an auxiliary method that takes a partial
solution and extends it.
private ListltPathPointgt extendedPathFrom (Room
room, ListltPathPointgt path) The specified
path extended from the specified Room to an
exit. Returns null if the path cannot be
extended to an exit. The specified path must be
empty or lead to the specified Room.
115Implementing backtracking
- The public method calls the auxiliary method with
an empty initial path
public ListltPathPointgt exitPathFrom (Room room)
return extendedPathFrom( room, new
DefaultListltPathPointgt())
116Implementing backtracking
private ListltPathPointgt extendedPathFrom (
Room room, ListltPathPointgt path) if
(room.isExit()) return path else
boolean found false ListltPathPointgt
solution null int i 0 while (i lt
room.connections().size() !found) //
get a Room to extend the path Room
nextRoom room.connections().get(i) if
(!pathContains(path, nextRoom))
ListltPathPointgt extendedPath path.copy()
extendedPath.add(new PathPoint(room,i))
solution extendedPathFrom(nextRoom,extendedPath)
found solution ! null
i i1 return solution //end else
117Object recursion
- Examine another form of recursion, called
structural recursion or object recursion. - Structural recursion uses object structure in a
recursive manner to derive problem solutions.
118Object recursion
- Two flavors of solver objects
- General problem solver,
- the trivial problem solver.
- We make these children of a common abstract
parent
119Object recursion
- Construct an odometer-like counter consisting of
a sequence of digits. - A digit turning over from 9 to 0 causes its left
neighbor to increment - A solution is simply a stable state of the
counter, one in which all digits are set. - to find first solution that is, reset all digits
to 0. - to find next solution increment the counter by
1. - There is a final solution, all digits are 9.
- We specify that attempting to find the next
solution after the final state will fail i.e., a
counter that is all 9s will not turn over to all
0s.
120Object recursion
- Digit general solver class.
- Each Digit instance is responsible for a single
digit of the solution. - Each Digit has an associate, the Digit to its
left. - A Digit extends solution provided by its
associate. - Digits are linked together to form the
counter. - The high-order (left-most) Digit has a NullDigit
as its associate. (it needs no associate). - NullDigit trivial solver class.
- The logic in the NullDigit simply ends the
recursion.
121Object recursion DigitCounter
- Note a Digit and its associate have the same
structure.
122Object recursion DigitCounter
public class DigitCounter private VirtualDigit
lowDigit // right-most digit /
Create a new DigitCounter with the specified
number of digits. _at_require digits gt 1
/ public DigitCounter (int digits)
VirtualDigit d new NullDigit() for (int i
1 i lt digits i i1) d new
Digit(d) lowDigit d
123Object recursion DigitCounter
public void first () lowDigit.first() pub
lic void next () lowDigit.next() public
boolean solved () return lowDigit.solved()
public String toString () return
lowDigit.toString() //end DigitCounter
124Object recursion DigitCounter
- DigitCounter contains a private interface
implemented by Digit and NullDigit.
private interface VirtualDigit public boolean
solved () public void first () public void
next () public String toString ()
125Object recursion Digit
- Digit class
- Implements VirtualDigit interface.
- Contains an int as data component for the digit.
- When given command first, instructs left neighbor
to find first number, and then sets itself
to 0. - When given the command next,
- it increments its digit if its not 9.
- If its digit is 9, it instructs its left neighbor
to increment, and sets itself to 0. - In each case checks neighbor was successful.
126Object recursion Digit
private class Digit implements VirtualDigit
private VirtualDigit associate // left nghb
private boolean solved // valid num
private int digit // my digit
public Digit (VirtualDigit associate)
this.associate associate this.digit
0 this.solved false public boolean
solved () return solved public void
first () associate.first() if
(associate.solved()) digit 0 solved
true else solved false
127Object recursion Digit
public void next () if (digit lt 9)
digit digit 1 solved true else
associate.next() if
(associate.solved()) digit 0 solved
true else solved false
public String toString () if
(solved) return associate.toString() digit
else return "No solution" //end Digit
128Object recursion NullDigit
private class NullDigit implements VirtualDigit
private boolean solved public NullDigit ()
this.solved false public boolean
solved () return solved public void
first () solved true public void next
() solved false public String toString
() if (solved) return "" else return
"No solution"