Another example of a recursive process is making paper chains.
Suppose we want to make paper chains out of paper
strips like that below.
Suppose you are asked to make a paper chain of length 4.
According to the process description, you must first create a chain of
length 3, then add a loop to it.
So the problem has two parts: a smaller version (
n=3) of the
original problem, and then a small amount of work to complete it.
That small amount of work will have to wait until the subproblem is
solved.
According to the process description, you must first create a chain of
length 2, then add a loop to it.
So the problem has two parts: a smaller version (
n=2) of the
original problem, and then a small amount of work to complete it.
Again, that small amount of work will have to wait until the subproblem is
solved.
Etc... Now the problem becomes n=1.
We have come to the
Base Case of the recursive process, and the
problem can be solved directly, as shown to the right.
But we must complete the problems that were
"put on hold,"
represented by the paper strips waiting to be linked in.
Complete the
n=2
problem by adding a loop to the chain resulting from
n=1:
Complete the
n=3
problem by adding a loop to the chain resulting from
n=2:
Finally, complete the
n=4
problem by adding a loop to the chain resulting from
n=3:
We can describe recursive processes in Racket through recursive
procedures.
n! = n × (n-1) × (n-2) × ... 2 × 1
Q: What is a subproblem of the factorial problem that is of the
same form?
-
(n-1) × (n-2) × ... 2 × 1 = (n-1)!
-
So, n! = n × (n-1)!
-
Similarly, (n-1)! = (n-1) × (n-2)!
-
And so on, till eventually, 1! = 1
-
An alternative mathematical definition of
factorial is:
n! | = | 1 if
n=1 |
| = | n × (n-1)!
otherwise |
-
The Base Case Imperative: In a recursive
procedure, all roads must lead to a base
case.
- Base Case: foo squares argument 0, because when given 0
foo returns 0, and the square of 0 is 0.
- Inductive Step: Assume that foo squares
n-1. Call this the Induction Hypothesis (IH).
- 1. (foo n) returns foo applied to n-1 plus 2n-1 (by
inspection of foo and elementary algebra)
- 2. foo applied to n-1 is (n-1)2 (by
the IH)
- 3. (n-1)2 = n2 - 2n + 1 (by elementary algebra)
- 4. (foo n) returns n2 - 2n + 1 + 2n - 1 (by steps
1, 2, and 3)
- 5. (foo n) returns n2 (by elementary algebra on 4)
Observations:
- If n < d then d does not divide n
- Otherwise, d divides n once plus however many times
it divides n-d
Example:
(quot 11 3) =
(quot 8 3) + 1 =
(quot 5 3) + 1 + 1 =
(quot 2 3) + 1 + 1 + 1 =
0 + 1 + 1 + 1 = 3
Nested
if expressions like that used in
quot can be
modeled using flowchart diagrams like the one below.
This ensures that exactly one among multiple possible actions is
performed.
In
quot:
test1:
(< d 0) |
action1:
return (- (quot n (- d))) |
test2:
(< n 0) |
action2:
return (- (quot (- n) d)) |
test3:
(< n d) |
action3:
return 0 |
|
action4:
return (+ 1 (quot (- n d) d))) |
The remainder when dividing integer
n by integer
d is the
difference between
n and the product of
d and the number
of times
d divides
n, i.e.
(quotient n d).
Example: the remainder when dividing
10 by
3 is:
10 - 3 × (quotient 10 3) =
10 - 9 =
1
(define remainder
(lambda (n d)
(- n (* d (quotient n d)))))
- Want a procedure num-digits that behaves like:
Expression | Value |
(num-digits 9475) | 4 |
(num-digits 1234567890) | 10 |
(num-digits 0) | 1 |
- Q: What similar, smaller problem is such that, if you had a
solution to it, would make the overall problem easy?
- A: The problem of determining the number of
digits in an integer that is one digit smaller.
Example:
Number of digits in 9475 | = | Number of digits in 947 | + | 1 |
| = | 3 | + | 1 |
| = | 4 | | |
- Q: How can we obtain 947 from 9475?
- A: Compute (quotient 9475 10)
General form:
(define num-digits
(lambda (n)
(if _________
_________
_________)))
- Q: What is the base case?
- A: When n < 10, the number of digits in n is
just 1.
(define num-digits
(lambda (n)
(if (< n 10)
1
_________)))
Q: What is the recursive case?
- A: Return 1 plus the result of calling num-digits
on (quotient n 10):
(define num-digits
(lambda (n)
(if (< n 10)
1
(+ 1
(num-digits (quotient n 10))))))
Q: How to make it work on negative integers?
- A: Return result of calling on (- n)
(define num-digits
(lambda (n)
(if (< n 0)
(num-digits (- n))
(if (< n 10)
1
(+ 1
(num-digits (quotient n 10)))))))