Analyzing recursive algorithms
- What is the
running time
of the following
recursive method:
public static void recurse(int[] A, int a, int b)
{
if ( b-a <= 1 )
doPrimitive();
else
{
doPrimitive();
recurse(A, a, (a+b)/2); // First half of array
recurse(A, (a+b)/2, b); // 2nd half of array
}
}
|
Analysis:
How many times will doPrimitive() be executed
when input of the recurse method is b-a = n ?
The analysis of recursive algorithms
require the use of:
recurrence relations....
|
|
Analyzing recursive algorithms
Analyzing recursive algorithms
Analyzing recursive algorithms
Analyzing recursive algorithms
-
Therefore:
the
recurrence relation
that represents the
running time is:
Let C(n) = # times that recurse() is executed when input = n
C(n) = 1 + 2*C(n/2) for n > 0, and C(1) = 1
We now proceed to solve this recurrence relation...
with "telescoping"
YouTube video on telescoping: click here
|
|
Analyzing recursive algorithms
-
Solving the
recurrence relation:
with
"telescoping":
Let C(n) = # times that recurse() is executed when input = n
C(n) = 1 + 2*C(n/2) for n > 0, and C(1) = 1
C(n) = 1 + 2*C(n/2) // We start with the general recurrence relation
// and reduce it to the base case
|
|
Analyzing recursive algorithms
-
We can use C(n) = 1 + C(n/2) to
obtain a
formula for
C(n/2)
by substituting
n ==> n/2:
Let C(n) = # times that recurse() is executed when input = n
C(n) = 1 + 2*C(n/2) for n > 0, and C(1) = 1
C(n) = 1 + 2*C(n/2) ==> C(n/2) = 1 + 2*C(n/4)
|
|
Analyzing recursive algorithms
-
Substitute the
expression for
C(n/2) in the
formula for
C(n):
Let C(n) = # times that recurse() is executed when input = n
C(n) = 1 + 2*C(n/2) for n > 0, and C(1) = 1
C(n) = 1 + 2*C(n/2) ==> C(n/2) = 1 + 2*C(n/4)
= 1 + 2*(1 + 2*C(n/4))
= 1 + 2 + 22*C(n/4)
|
|
Analyzing recursive algorithms
-
We can use C(n) = 1 + C(n/2) to
obtain a
formula for
C(n/4)
by substituting
n ==> n/4:
Let C(n) = # times that recurse() is executed when input = n
C(n) = 1 + 2*C(n/2) for n > 0, and C(1) = 1
C(n) = 1 + 2*C(n/2) ==> C(n/4) = 1 + 2*C(n/8)
= 1 + 2*(1 + 2*C(n/4))
= 1 + 2 + 22*C(n/4)
|
|
Analyzing recursive algorithms
-
Substitute the
expression for
C(n/4) in the
formula for
C(n):
Let C(n) = # times that recurse() is executed when input = n
C(n) = 1 + 2*C(n/2) for n > 0, and C(1) = 1
C(n) = 1 + 2*C(n/2) ==> C(n/4) = 1 + 2*C(n/8)
= 1 + 2*(1 + 2*C(n/4))
= 1 + 2 + 22*C(n/4)
= 1 + 2 + 22*(1 + 2*C(n/8))
= 1 + 2 + 22 + 23*C(n/8)
|
|
Analyzing recursive algorithms
-
We can see a
pattern and can
predict the
next progression:
Let C(n) = # times that recurse() is executed when input = n
C(n) = 1 + 2*C(n/2) for n > 0, and C(1) = 1
C(n) = 1 + 2*C(n/2) ==> C(n/4) = 1 + 2*C(n/8)
= 1 + 2*(1 + 2*C(n/4))
= 1 + 2 + 22*C(n/4)
= 1 + 2 + 22*(1 + 2*C(n/8))
= 1 + 2 + 22 + 23*C(n/8)
= 1 + 2 + 22 + 23 + 24*C(n/16)
(1) get an extra 23
(2) C(n/8) becomes C(n/16)
(If you don't see the pattern, substitute C(n/8) and work it out)
|
|
Analyzing recursive algorithms
-
Repeat these
steps
until
we will get
C(1):
Let C(n) = # times that recurse() is executed when input = n
C(n) = 1 + 2*C(n/2) for n > 0, and C(1) = 1
C(n) = 1 + 2*C(n/2) ==> C(n/4) = 1 + 2*C(n/8)
= 1 + 2*(1 + 2*C(n/4))
= 1 + 2 + 22*C(n/4)
= 1 + 2 + 22*(1 + 2*C(n/8))
= 1 + 2 + 22 + 23*C(n/8)
= 1 + 2 + 22 + 23 + 24*C(n/16)
....
= 1 + 2 + 22 + 23 + ... + 2k*C(n/(2k))
where n/(2k) = 1 <==> 2k = n
|
|
Analyzing recursive algorithms
-
Substitute
C(n/(2k)) with
C(1):
Let C(n) = # times that recurse() is executed when input = n
C(n) = 1 + 2*C(n/2) for n > 0, and C(1) = 1
C(n) = 1 + 2*C(n/2) ==> C(n/4) = 1 + 2*C(n/8)
= 1 + 2*(1 + 2*C(n/4))
= 1 + 2 + 22*C(n/4)
= 1 + 2 + 22*(1 + 2*C(n/8))
= 1 + 2 + 22 + 23*C(n/8)
= 1 + 2 + 22 + 23 + 24*C(n/16)
....
= 1 + 2 + 22 + 23 + ... + 2k*C(n/(2k))
where n/(2k) = 1 <==> 2k = n
= 1 + 2 + 22 + 23 + ... + 2k*C(1) (with k = log(n))
|
|
Analyzing recursive algorithms
-
Substitute
C(1) with
1:
Let C(n) = # times that recurse() is executed when input = n
C(n) = 1 + 2*C(n/2) for n > 0, and C(1) = 1
C(n) = 1 + 2*C(n/2) ==> C(n/4) = 1 + 2*C(n/8)
= 1 + 2*(1 + 2*C(n/4))
= 1 + 2 + 22*C(n/4)
= 1 + 2 + 22*(1 + 2*C(n/8))
= 1 + 2 + 22 + 23*C(n/8)
= 1 + 2 + 22 + 23 + 24*C(n/16)
....
= 1 + 2 + 22 + 23 + ... + 2k*C(n/(2k))
where n/(2k) = 1 <==> 2k = n
= 1 + 2 + 22 + 23 + ... + 2k*C(1) (with k = log(n))
= 1 + 2 + 22 + 23 + ... + 2k (with k = log(n))
|
|
Analyzing recursive algorithms
-
Work out the
geometric sum:
Let C(n) = # times that recurse() is executed when input = n
C(n) = 1 + 2*C(n/2) for n > 0, and C(1) = 1
C(n) = 1 + 2*C(n/2) ==> C(n/4) = 1 + 2*C(n/8)
= 1 + 2*(1 + 2*C(n/4))
= 1 + 2 + 22*C(n/4)
= 1 + 2 + 22*(1 + 2*C(n/8))
= 1 + 2 + 22 + 23*C(n/8)
= 1 + 2 + 22 + 23 + 24*C(n/16)
....
= 1 + 2 + 22 + 23 + ... + 2k*C(n/(2k))
where n/(2k) = 1 <==> 2k = n
= 1 + 2 + 22 + 23 + ... + 2k*C(1) (with k = log(n))
= 1 + 2 + 22 + 23 + ... + 2k (with k = log(n))
Let:
S = 1 + 2 + 22 + 23 + ... + 2k
2S = 2 + 22 + 23 + ... + 2k + 2k+1
=> S = 2k+1 - 1
|
|
Analyzing recursive algorithms
-
We found an
expression for
C(n):
Let C(n) = # times that recurse() is executed when input = n
C(n) = 1 + 2*C(n/2) for n > 0, and C(1) = 1
C(n) = 1 + 2*C(n/2) ==> C(n/4) = 1 + 2*C(n/8)
= 1 + 2*(1 + 2*C(n/4))
= 1 + 2 + 22*C(n/4)
= 1 + 2 + 22*(1 + 2*C(n/8))
= 1 + 2 + 22 + 23*C(n/8)
= 1 + 2 + 22 + 23 + 24*C(n/16)
....
= 1 + 2 + 22 + 23 + ... + 2k*C(n/(2k))
where n/(2k) = 1 <==> 2k = n
= 1 + 2 + 22 + 23 + ... + 2k*C(1) (with k = log(n))
= 1 + 2 + 22 + 23 + ... + 2k (with k = log(n))
= 2k+1 - 1 = 2log(n)+1 - 1
|
|
Analyzing recursive algorithms
-
We found an
expression for
C(n):
Let C(n) = # times that recurse() is executed when input = n
C(n) = 1 + 2*C(n/2) for n > 0, and C(1) = 1
C(n) = 1 + 2*C(n/2) ==> C(n/4) = 1 + 2*C(n/8)
= 1 + 2*(1 + 2*C(n/4))
= 1 + 2 + 22*C(n/4)
= 1 + 2 + 22*(1 + 2*C(n/8))
= 1 + 2 + 22 + 23*C(n/8)
= 1 + 2 + 22 + 23 + 24*C(n/16)
....
= 1 + 2 + 22 + 23 + ... + 2k*C(n/(2k))
where n/(2k) = 1 <==> 2k = n
= 1 + 2 + 22 + 23 + ... + 2k*C(1) (with k = log(n))
= 1 + 2 + 22 + 23 + ... + 2k (with k = log(n))
= 2k+1 - 1 = 2log(n)+1 - 1
= 2log(n)*21 - 1 = 2n - 1
|
|
DEMO:
demo/13-analysis/Demo11.java
❮
❯