Vectors and Vector Operations

advertisement
1.10 Recursion
A recursive definition of a term is a definition that involves the term itself in the
definition of the term.
A recursive formula (or recursive function) is a formula (or function) that involves itself
in its definition.
A recursive function in a computer program is one that calls itself.
In the last two cases you need to be careful you don't get caught in an infinite loop.
Example 1. Factorials. Recall that the factorial of a positive integer n is the product of
all the integers from 1 to n, i.e.
n! = 123…n
For example
4! = 1234 = 24
Many books make the special definition in the case that n = 0 by setting 0! = 1. In order
to make this into a recursive definition, note that
n! = 123…(n-1)n = [123…(n-1)]  n = n [(n-1)!]
Thus
n! = n [(n-1)!]
Notice that this formula for n! involves a factorial on the right. It is this aspect that
makes the formula recursive. However, this formula is not a complete definition of n!.
We need to augment it by the special case where n = 0. So a complete recursive
definition of n! would be the following.
(1)
 n [(n-1)!]
n! = 
 1
if n  1
if n = 0
To use this definition to compute 4! we would proceed as follows. Putting n = 4 into the
definition (1) we get
(2)
4! = 4(4-1)! = 43!
At this point we leave off the calculation of 4! and use the definition to compute 3!.
Putting n = 3 into (1) gives
1.10 - 1
(3)
3! = 3(3-1)! = 32!
At this point we leave off the calculation of 3! and use (1) to compute 2!.
(4)
2! = 2(2-1)! = 21!
Now we use (1) with n = 1.
(5)
1! = 1(1-1)! = 10!
Now we use (1) with n = 0. However, in this case (1) simply says
0! = 1
We put this into (5) giving
1! = 10! = 11 = 1
We put this into (4) giving
2! = 21! = 21 = 2
We put this into (3) giving
3! = 32! = 32 = 6
Finally, we put this into (2) giving
4! = 43! = 46 = 24
The definition (1) can be used as the basis of a recursive function in a computer program.
For example, in C one could convert (1) into the following.
int factorial( int n )
{ if (n == 0)
return 1;
else
return n * factorial( n – 1 );
}
The recursive computation of 4! above amounted to a loop. It turns out that in computer
programming, many things that can be done with a loop can be done with a recursive
function instead.
Example 2. Consider the computation of the sum of the squares of the consecutive
integers from 1 to n, i.e.
1.10 - 2
12 + 22 + 32 + … + n2
For example, if n = 4 we would get
12 + 22 + 32 + 42 = 1 + 4 + 9 + 16 = 30
In order to make this into a recursive definition, we give the sum a name and note that
(6)
Sn = 12 + 22 + … + (n-1)2 + n2 = Sn-1 + n2
For example,
S4 = 12 + 22 + 32 + 42 = S3 + 42
We need to augment (6) for the special case where n = 0 by setting S0 = 0. So a complete
recursive definition of Sn would be the following.
(7)
Sn
 Sn-1 + n2
= 
 0
if n  1
if n = 0
For example, in C one could convert (7) into the following.
int S( int n )
{ if (n == 0)
return 0;
else
return S(n – 1) + n2;
}
Recursive definitions of functions defined for positive integers are often called
recurrence relations or difference equations. We shall look at these in more detail in
chapter 5.
Recursive definitions can also be used for character strings.
Example 3. The reversal of a string is the new string with the characters in the original
string arranged in the reverse order. Thus if s = "c1c2c3…cn" is the string consisting of
the characters c1, c2, c3, …, cn then
rev(s) = reversal of s
= "cncn-1…c2c1"
For example if s = "john", then rev(s) = "nhoj".
In order to make this into a recursive formula, note that
1.10 - 3
rev("c1c2c3…cn") = "cn" + "cn-1…c2c1" = "cn" + rev("cn-1…c2c1")
= sn + rev(s1,n-1) = sLen(s) + rev(s1,Len(s)-1)
where
+ = concatenation of strings
sj = the string consisting of the jth character of s
sj,k = the string consisting of characters j through k of s
Len(s) = the number of characters in s.
We supplement this formula by defining the reversal of the null string "" to be the null
string itself. So
(8)
if s  ""
 sLen(s) + rev(s1,Len(s)-1)
rev(s) = 
 ""
if s = ""
To use this definition to compute rev("john") we would proceed as follows.
rev("john") = "n" + rev("joh")
rev("joh") = "h" + rev("jo")
rev("jo") = "o" + rev("j")
rev("j") = "j" + rev("")
rev("") = ""
rev("j") = "j" + "" = ""
rev("jo") = "o" + "j" = "oj"
rev("joh") = "h" + "oj" = "hoj"
rev("john") = "n" + "hoj" = "nhoj"
For example, in C one could convert (8) into the following.
1.10 - 4
string rev(string s)
{ int n;
n = s.length();
if (s == "")
return s;
else
return s[n-1] + rev(s.substr(0,n-1));
}
Sometimes a recursive definition is simpler than a non-recursive one.
Example 4 (The Fibonacci sequence). The Fibonacci sequence f0, f1, f2, …, fn, … starts
out with f0 = 1 and f1 = 1. After that each element is the sum of the two previous
elements. See table at right. A recursive definition is
(9)
fn
 fn-2 + fn-1
= 
 1
if n  2
if n = 0 or n = 1
In C one could convert (9) into the following.
int f( int n )
{ if ((n == 0) || (n == 1))
return 1;
else
return f(n – 2) + f(n – 1);
}
n
0
1
2
3
4
5
6
7
8
9
10
fn
1
1
2
3
5
8
13
21
34
55
89
We shall show later that
fn
n
n
5 + 1 1 + 5
5 - 1 1 - 5

 +


=
2 5  2 
2 5  2 
 0.72 (1.62)n + 0.28 (- 0.62)n
Since (- 0.62)n  0 as n   it follow that for large n one has
fn  0.72 (1.62)n
i.e. the fn grow exponentially fast with n.
Even though the recursive definition of fn allows one to write a simple computer program
to compute fn, in this case the recursive program runs much slower than a non-recursive
one since the recursive program doesn't take advantage of the previous computation of
f(n – 2) when it computes f(n – 1). Here is a non-recursive version.
1.10 - 5
int f( int n )
{ int fn, fnm1, j;
fnm1 = 1;
fn = 1;
for (j = 2; j <= n, j++)
{
nextf = fn + fnm1;
fnm1 = fn;
fn = nextf;
}
else
return fn;
}
1.10 - 6
Download