The simplest example is with factorial. The "base case" is when we hit 0 or 1, we want to return 1. By identifying and defining this case first you ensure that your program's execution will be bounded (which is normally what we want):
def factorial(n):
if n == 0 or n == 1:
return 1
# recursive case(s)
This is an incomplete program, the next part is to identify each of the recursive calls. In this case there's just one, and it's achieved by reducing `n` by 1 and multiplying the result of the call by the current `n`:
def factorial(n):
if n == 0 or n == 1:
return 1
return n * factorial(n - 1)
And if you're using a non-braindead interpreter/compiler you'd make this more efficient by using tail-calls (these get optimized away by reasonable language implementations, the main Python implementation is not reasonable):
def factorial(n, accum=1):
if n == 0 or n == 1:
return accum
return factorial(n - 1, accum * n)
For more complex cases, consider a binary tree or node in an abstract syntax tree (AST). Assuming an ordered binary tree (left node is less than current node, right is greater than the current node) and a search over the tree (this is also easy to do without recursion at all but for the illustration):
Assume the node is something like this:
@dataclass
class Node:
item: int = 0
left: Node = None
right: Node = None
def search(node, value):
# 1st base case: the value was not found
if node is None:
return False
# 2nd base case: the value was found
if node.item == value:
return True
Again, at this point the program is not complete but we've identified the two base cases. The next step is to figure out the recursive step(s). In this case there are two recursive steps but only one will be taken (if we aren't at the base cases yet): go left or go right.
def search(node, value):
if node is None:
return False
if node.item == value:
return True
if node.item < value:
return search(node.left, value)
if node.item > value:
# technically this test will always be true if we reach this point
# so the right search can be made unconditional. I put this here
# to be more explicit, remove the test to be more efficient.
return search(node.right, value)
If your data structure or problem has a recursive structure, you can use this approach.
Assume the node is something like this:
Again, at this point the program is not complete but we've identified the two base cases. The next step is to figure out the recursive step(s). In this case there are two recursive steps but only one will be taken (if we aren't at the base cases yet): go left or go right. If your data structure or problem has a recursive structure, you can use this approach.