Java Methods A & AB - Skylight Publishing
Download
Report
Transcript Java Methods A & AB - Skylight Publishing
Java Methods
A & AB
Object-Oriented Programming
and Data Structures
Maria Litvin ● Gary Litvin
C H
T
A
P
T P
R
E
R — 2 2
Recursion Revisited
Copyright © 2006 by Maria Litvin, Gary Litvin, and Skylight Publishing. All rights reserved.
Objectives:
• Take a fresh look at recursion
• Learn when to use recursion and when to
stay away from it
• Learn to prove the correctness of recursive
methods
• Get ready for the Game of Hex lab
22-2
Recursion Basics
• A recursive method has a base case (or
several base cases) and a recursive case
In the base case, there are no recursive calls
In the recursive case, the method calls itself, but
for a “smaller” task
• Recursive calls must eventually converge to a
base case, when recursion stops
22-3
Example 1
public String reverse (String s)
{
Base case
if (s.length() < 2)
(nothing to do)
return s;
return reverse (s.substring (1)) +
s.charAt(0);
}
Recursive case
ABCD
Take
substring
A
BCD
Reverse
substring
A
DCB
Append the
first char
DCBA
22-4
Need x7
Example 2
7 / 2 == 3
public double pow (double x, int n)
{
Base case
if (n == 0)
return 1.0;
double y = pow (x, n / 2);
y *= y;
if ( n % 2 != 0 )
y *= x;
return y;
}
Recursive
case
First get
y = x3
Then square
y*y = x6
7 is odd, so
y *= x
Caution: NOT
double y = pow(x, n / 2) *pow(x, n / 2);
22-5
ArrayList fruits = new ArrayList ();
fruits.add ("apples");
fruits.add ("bananas");
Example 3
ArrayList snacks = new ArrayList ();
snacks.add ("chips");
snacks.add ("pretzels");
ArrayList food = new ArrayList ();
food.add ("Fruits");
food.add (fruits);
food.add ("Snacks");
food.add (snacks);
Recursive calls to
ArrayList’s toString
method take place
here
System.out.println (food);
Output:
[Fruits, [apples, bananas], Snacks, [chips, pretzels]]
22-6
Example 4
public boolean degreeOfSeparation (
Set<Person> people, Person p1, Person p2, int n)
{
Base case
if (n == 1)
{
return p1.knows (p2);
}
Recursive
else
case
{
for (Person p : people)
{
if (p1.knows (p) &&
degreeOfSeparation (people, p, p2, n-1))
return true;
}
return false;
}
}
p1
p
p2
22-7
When to Use Recursion
• Recursion is especially useful for handling
nested structures and branching processes
22-8
1
Example 5
public void traverse (TreeNode root)
{
if (root != null)
Recursive case
{
display (root.getValue ());
1
traverse (root.getLeft ());
2
traverse (root.getRight ());
3
}
}
2
3
22-9
1
Example 6
ABCD
DBC A
ABCD
public void permutations
(StringBuffer str, int n)
{
if (n <= 1)
System.out.println (str);
else
Recursive case
{
for ( int i = 0; i < n; i++ )
{
swap (str, i, n-1);
permutations (str, n-1);
1-4
swap (str, n-1, i);
}
}
}
2
ABCD
ADC B
ABCD
3
ABCD
ABD C
ABCD
4
ABCD
ABC D
ABCD
BCD A
CBD A
CDB A
DCB A
BDC A
DBC A
DCA B
CDA B
CAD B
ACD B
DAC B
ADC B
BDA C
DBA C
DAB C
ADB C
BAD C
ABD C
BCA D
CBA D
CAB D
ACB D
BAC D
ABC D
22-10
Use Recursion
• When it significantly simplifies code
without significant perfomance penalty
Do Not Use Recursion
• When a method allocates large local arrays
• When a method unpredictably changes fields
• When iterative solutions is just as simple
22-11
Just As Easy With Iterations
public String reverse (String s)
{
if (s.length () < 2)
return s;
public String reverse (String s)
{
String r = "";
for (int i = s.length( ) - 1;
i >= 0; i--)
r += s.charAt (i);
return r;
return reverse (
s.substring(1)) + s.charAt(0);
}
}
22-12
Not Easy Without Recursion
public void traverse (TreeNode root)
{
if (root != null)
{
display (root.getValue ());
traverse (root.getLeft ());
traverse (root.getRight ());
}
}
Need your own
stack to do this
without recursion!
Rule of thumb: use recursion when the
process is branching, that is, when the
method is called recursively more than
once or within a loop
22-13
Very Inefficient Recursive Code
public long fibonacci (int n)
{
if (n < 2)
return 1;
else
return fibonacci (n-2) +
fibonacci (n-1);
}
fibonacci(100) takes
50 years to run
public long fibonacci (int n)
{
long f1 = 1, f2 = 1, next;
while (n > 2)
{
next = f1 + f2;
f1 = f2;
f2 = next;
n--;
}
return f2;
}
fibonacci(100) takes a
few microseconds to run
22-14
Recursion and Math Induction
• Recursive methods are hard to trace in a
conventional way.
• A recursive method can be proven correct
using math induction.
• Other properties of a recursive method
(running time, required space, etc.) can be
obtained by using math induction.
22-15
Math Induction Basics
• You have a sequence of statements
P1, P2, P3, ... Pn-1 , Pn , ...
• Suppose P1 is true (“base case”).
• Suppose you can prove that for any n > 1, if
P1, ... Pn-1 are all true then Pn must be true,
too.
It is often possible to prove that if Pn-1
is true then Pn is also true.
• Then you can conclude (“by math induction”)
that Pn is true for any n 1
22-16
Math Induction Example:
Prove that for any n 1
1 + 2 + 4 + ... + 2n = 2n+1 - 1
Proof:
1. If n = 1 then 1 + 2 = 22 - 1
2. Suppose (induction hypothesis)
1 + 2 + 4 + ... + 2n-1 = 2n - 1
Then
1 + 2 + 4 + ... + 2n =
(1 + 2 + 4 + ... 2n-1) + 2n = (2n - 1) + 2n =
2·2n - 1 = 2n+1 - 1
By math induction, the equality is true for any n 1, q.e.d.
22-17
Math Induction and Recursion
public String reverse (String s)
{
if (s.length( ) < 2)
return s;
return reverse (s.substring(1))
+ s.charAt(0);
}
Let us verify that this method works, that is, reverse(s)
indeed returns the reverse of s. We will use math
induction “over the length of s.”
To be continued...
22-18
Proof
public String reverse (String s)
{
if (s.length < 2)
return s;
Let n = s.length();
1. If n = 0 or n = 1 then reverse
return reverse (s.substring(1))
+ s.charAt(0);
}
works because the string
remains unchanged
2. Suppose (induction hypothesis)
reverse works for any string of length
n-1. Then it works for s.substring(1).
So we reverse that substring and then
append the first char of s at the end.
We get the reverse of s.
By math induction, reverse works for
a string of any length, q.e.d.
22-19
The Tower of Hanoi
• Objective: move the tower from one peg to
another, moving one disk at a time and
never placing a larger disk on top of a
smaller one; you can use the spare peg.
• This puzzle was invented by François
Edouard Anatole Lucas and published in
1883
22-20
The Tower of Hanoi:
Recursive Solution
For n disks:
• If n = 1, just move the
disk to the desired peg.
• If n > 1
Move the top n-1 disks
to a spare peg (recursive
step).
Move the bottom disk to
the desired peg.
Move all n-1 disks from
the spare to the desired
peg (recursive step).
22-21
The Game of Hex
B
W
W
B
• Two players take turns placing a stone of
their color
• Objective: connect your pair of the opposite
sides of the board with stones of your color
22-22
The Game of Hex (cont’d)
• Computer representation of the board
in a 2-D array
W
B
B
Each cell has
six “logical”
neighbors
W
22-23
The Game of Hex (cont’d)
• To detect a win, determine whether any
“blob” (connected group of stones)
touches the opposite sides
22-24
The Game of Hex (cont’d)
• This kind of task falls into the category of
“area fill” tasks
22-25
Review:
• What is recursion?
• How is recursion implemented in a
computer?
• What kinds of applications especially
benefit from recursion?
• Give an example of a task that can be
programmed recursively and also, as
easily, with iterations.
22-26
Review (cont’d):
• Give an example of a task that would be
rather hard to program without recursion.
• Give an example of a method that is too
slow in a naïve recursive implementation.
• What mathematical tool is very useful for
understanding recursive methods and
proving them correct?
22-27
Review (cont’d):
• What is the number of moves necessary
to solve the Tower of Hanoi puzzle with
1, 2, 3, ..., n disks? How would you prove
your hypothesis?
• Can you come up with an idea for a
recursive algorithm for “area fill”?
22-28