A recursive subroutine solves a problem by calling itself on a smaller version of the same problem until it reaches a case it can answer directly. You write and trace recursive algorithms, follow the call stack as it winds up and unwinds, and judge when recursion is the right tool.
A recursive subroutine is one that is defined in terms of itself: it calls itself. It must have a base case, a condition where it returns a result without calling itself, and a general (recursive) case that calls itself with a value that moves closer to the base case. Each call is placed on the call stack as a stack frame holding its return address, parameters and local variables. When the base case is reached the calls return one by one in reverse order: the stack unwinds. With no reachable base case the stack fills up: stack overflow.
Factorial is the classic first example: 4! = 4 × 3 × 2 × 1, and 4! = 4 × 3!. That second form defines the factorial in terms of a smaller factorial, which is exactly what a recursive function does.
FUNCTION Factorial(n : INTEGER) RETURNS INTEGER
IF n = 0 THEN
RETURN 1 // base case
ELSE
RETURN n * Factorial(n - 1) // general case
ENDIF
ENDFUNCTION
Factorial appears inside its own definition.n = 0 returns 1 without any further call. This is the stopping condition.n * Factorial(n - 1) calls itself with n reduced by 1, so every call moves towards the base case.Factorial(4).| Call | n | Waits for | Returns |
|---|---|---|---|
| 1 | 4 | 4 * Factorial(3) | 24 |
| 2 | 3 | 3 * Factorial(2) | 6 |
| 3 | 2 | 2 * Factorial(1) | 2 |
| 4 | 1 | 1 * Factorial(0) | 1 |
| 5 | 0 | (base case) | 1 |
Five calls in total; the value 24 is returned to the original caller.
Power(Base, Exp) returns 1 if Exp = 0, otherwise Base * Power(Base, Exp - 1). How many calls are made by Power(3, 4), and what is returned?A base case that is never reached is as bad as none. Factorial(−1) calls Factorial(−2), then −3, ... and never meets n = 0, so the stack overflows. State that each call must move towards the base case.
Where the work happens matters. Anything before the recursive call runs on the way down (winding); anything after it runs on the way back up (unwinding), in reverse order. In the lab, run the in-order, pre-order and post-order traversals of the tree: each is a three-line recursive procedure.
PROCEDURE Mystery(n : INTEGER)
IF n > 1 THEN
CALL Mystery(n DIV 2)
ENDIF
OUTPUT n MOD 2
ENDPROCEDURE
PROCEDURE InOrder(Node : INTEGER)
IF Node <> NullPointer THEN
CALL InOrder(Tree[Node].LeftPointer)
OUTPUT Tree[Node].Data
CALL InOrder(Tree[Node].RightPointer)
ENDIF
ENDPROCEDURE
CALL Mystery(13).Show(n) does: IF n > 0 THEN OUTPUT n, CALL Show(n - 2), OUTPUT n * 10, ENDIF. What is output by CALL Show(5)?In a trace, do not output a value when a call is made if the OUTPUT is after the recursive call. Write each call on a new row, and fill in its output only when control returns to it.
Four quick checks. Each correct answer earns XP and records this skill on your profile.
What is the base case in a recursive subroutine?
What does Factorial(3) return?
In the lab, which traversal outputs the values of a binary search tree in ascending order?
Which output does a recursive procedure give for a line placed after its recursive call?
Recursion only works because each call gets its own copy of its parameters and local variables, and remembers where to return to. The compiler arranges this with a stack, the same LIFO structure you implemented in the last lesson.
| Recursion is beneficial when... | Iteration is better when... |
|---|---|
| the problem is naturally recursive: trees, traversals, divide and conquer (binary search, merge sort), nested structures | a simple loop does the job, as for factorial or summing a list |
| the recursive version is much shorter and clearer, so easier to write and check | memory is limited: iteration uses O(1) stack space |
| the depth of recursion is small, so the extra memory is not a problem | speed matters: every call costs time to push and pop a frame |
FUNCTION Fib(n : INTEGER) RETURNS INTEGER
IF n <= 1 THEN
RETURN n
ELSE
RETURN Fib(n - 1) + Fib(n - 2)
ENDIF
ENDFUNCTION
Fib(5) is evaluated?FUNCTION Factorial(n : INTEGER) RETURNS INTEGER
DECLARE Result : INTEGER
DECLARE i : INTEGER
Result ← 1
FOR i ← 1 TO n
Result ← Result * i
NEXT i
RETURN Result
ENDFUNCTIONIt uses a fixed amount of memory (no stack frame per step), so it cannot cause a stack overflow, and it avoids the time spent on calls and returns."Recursion is faster" is usually wrong. A recursive solution is often shorter and clearer, but it normally uses more memory and more time than an equivalent loop because of the stack frames.
Unlocks once the four checks above are done. Worth more XP, written to A Level Paper 3 and Paper 4 standard.
Which item is NOT stored in a stack frame when a recursive call is made?
A recursive function has no reachable base case. What happens when it runs?
Mystery(n) calls Mystery(n DIV 2) when n > 1, then outputs n MOD 2. What does CALL Mystery(10) output?
When is recursion most likely to be the better choice than iteration?
This skill is now recorded on your profile. Keep the chain going.