This idea can seem paradoxical when you're just getting started, so we'll go through an example of how the computer really handles it in order to explain away the paradox. The upshot is that we have the same function, yes, but it is one call of the function that in turn makes a separate call to the same function, but with different arguments.
|
|
Consider the following program.
#include <iostream>
using namespace std;
int f(int k);
int main()
{
cout << f(10) << endl;
return 0;
}
int f(int k)
{
int a = k*k;
int b = f(k + 1);
return a + b;
}
Let's run the code:
$ ./a.out
Segmentation fault (core dumped)
[Exit 139 (SEGV)]
The program crashes.
fact above, the base case is when n
is 1.
f in the above, it always make a
recursive call. In other words, there is no base case.
|
Q. Specify the base case of this function.
Answer: When
|
k as
input and returns the value of 12 + 22 +
32 + ... + k2 .
It is a simple problem that we can concentrate on using recursion.
When you're setting out to write a recursive function, you at least have a prototype in mind. In this case that'll be
int sumsquare(int k);
That part is easy, and no recursion is involved.
In other words, for what inputs can we automatically just spit out the answer without having to do any real work? In particular, without needing a recursive call?
For this problem, I'm asking what values of k
are particularly easy to give the answer to? Of course,
since we're assuming that k is positive, the
easiest value for k is 1. If k is
one we can just immediately return 1. So that gives us our
base case.
// Base case
if (k == 1)
return 1;
How would the answer to a "smaller" problem of the same kind help get the answer to the original problem. In other words, if I just assume that the function (which I already have the prototype for) just "works" for smaller inputs, how will that help me get the answer?
For this problem, what I'm asking is this: How would the
answer to sumsquare(k-1) help me figure out the
answer to sumsquare(k)? Well, all I'd need to
add to the result of sumsquare(k-1) is a
k2, and I'd have the answer to
sumsquare(k).
sumsquare(1) : 1*1 sumsquare(2) : 1*1 + 2*2 sumsquare(3) : 1*1 + 2*2 + 3*3 ... sumsquare(k-1): 1*1 + 2*2 + 3*3 + ... + (k-1)*(k-1) sumsquare(k) : 1*1 + 2*2 + 3*3 + ... + (k-1)*(k-1) + k*kThis then gives us our recursive case:
// Recursive case
int p = sumsquare(k - 1);
int ans = p + k*k;
return ans;
sumsquare would work right when
we called sumsquare(k - 1).
So, here's the complete function:
int sumsquare(int k)
{
// Base case
if (k == 1)
return 1;
// Recursive case
int p = sumsquare(k - 1);
int ans = p + k*k;
return ans;
}
For example, suppose I had a function
factorialSmall that computed the factorial of its
argument, but only for numbers less than 10. How could
I use it to solve factorial 10? Easy:
10*factorialSmall(9) |
Now, suppose factorialSmall worked for any number
less than some value n, but I'm not telling you exactly what n is.
How could I compute factorial(n)? Easy:
n*factorialSmall(n-1) |
Great! Now I've got my recursive case!
**********
*********
********
*******
******
*****
****
***
**
*
Take a look at the solution
int gcd(int a, int b)
{
int r;
while( b != 0 )
{
r = a % b;
a = b;
b = r;
}
return a;
}
The way Euclid would've phrased his GCD
algorithm would be more like this: If A and
B (okay, he was greek, so it probably would've
been α and β ...) are two integers with A >= B >=
0 then the GCD of A and
B is given by:
B = 0 then the GCD is AB > 0 then the GCD is the same as
the GCD of B and A%B.|
Sierpinski gasket
|
Fern
|
Escher (Circle Limit IV Heaven Hell)
|
|
Natural language processing
| ||