Recursion solves a problem by invoking the same procedure on smaller instances, with base cases answered directly. For merge sort, an empty or one-entry array is already sorted, and every larger array is split into two shorter parts. The decreasing lengths justify termination; a self-call without a progress rule would not suffice.
A recursive procedure refers to itself, directly or through another procedure. A recursive call starts another invocation, with its own arguments and local variables; the caller can wait for its returned output. A base case supplies an answer without further recursive calls. To establish algorithm termination, also show that every recursive call progresses in a well-founded relation. “Smaller” means smaller in that chosen relation: argument values need not all decrease, and the arguments need not even be numbers.
Recursion is especially expressive when a data structure already decomposes into smaller structures. A binary tree has two child subtrees, so structural recursion can follow its shape. A short rule for each case can describe an entire traversal or computation. The distinction between a recursive procedure and the recursive process it generates helps connect that compact description to its resource use.[ref]
Structure and Interpretation of Computer Programs by Harold Abelson and others. Structure and Interpretation of Computer Programs, second edition, §1.2.1: procedure versus process; §1.2.2: closing discussion before Counting change, hierarchical data and straightforward definitions
A recursive definition in which returning around a recursive dependency requires progress of the kind relevant to its semantics. In communicating sequential processes, the visible guard must survive CSP hiding; a loop whose apparent guard becomes a CSP internal action is not visibly guarded.
Two or more functions are mutually recursive when their definitions call one another in a cycle. Two algebraic data types can likewise be mutually recursive when constructors of each refer to the other. For alternating sequences
Zig a b and Zag b a, descending one constructor exchanges the type parameters; a pair of mapping functions must exchange its arguments correspondingly. A mutually recursive fold may have two independent result types : its handlers have types a -> s -> r and b -> r -> s, with empty results of types r and s. Equality of the two result types is not required by type inference.A recursion tree records recursive calls as nodes and their direct recursive subcalls as children. Its node labels can record the work done outside those subcalls. Summing the work over levels or charging it to nodes proves a total running time bound. For , level has approximately instances of size , so its nonrecursive work is . Summing those quantities explains the cases of the master theorem.
If , the displayed identity expresses the decrease of the potential across a split. Here is the binary entropy function. If every split fraction stays in for a fixed , the potential decreases by at least . Consequently, for a recurrence relation with linear work at each split, the inductive hypothesis closes when and covers the base cases. This is a proof by the substitution method for a recurrence of an time complexity bound without requiring equal subproblem sizes.
Recursion in which the recursive call is the last operation required to obtain the current call's result. An accumulator can encode the state that would otherwise be updated by a loop. A suitable compiler can replace the call by a jump, avoiding growing call stack storage. In Scala, a tail-recursion annotation requests a check that the recursive method is eligible for this transformation.
A procedure whose definition invokes itself directly or indirectly. This is a property of its programming language syntax. It does not determine whether execution accumulates unfinished operations.[ref]
Structure and Interpretation of Computer Programs by Harold Abelson and others. Structure and Interpretation of Computer Programs, second edition, §1.2.1: paragraph beginning “In contrasting iteration and recursion”
A computation that retains pending operations while further calls run, then completes those operations as results return. A recursive procedure can instead describe an iterative process: passing an updated accumulator onward may leave no arithmetic pending. Avoiding growing call stack storage in that case depends on the implementation. A fixed number of variables also does not imply fixed storage in bits when their integer values grow.[ref]
Structure and Interpretation of Computer Programs by Harold Abelson and others. Structure and Interpretation of Computer Programs, second edition, §1.2.1: deferred operations, state variables, and implementation dependence of space use; bit-storage qualification added here
For a natural number , the factorial satisfies and for . The following description includes the zero base case explicitly; a negative or nonintegral input is outside its precondition:For , the arguments on descent are . Each positive-argument invocation postpones one multiplication until its recursive call returns. At the deepest point, the call stack has five stack frames: four suspended callers and the active zero base case. The invocation at zero returns to the invocation at one, rather than finishing the entire computation. Returns then giveA stack frame retains the caller's argument and where to resume. When the invocation at three receives , it uses its own , obtains , and returns that value to the invocation at four. The recursive calls share a definition, but their local variables belong to separate invocations.
F(n):
require n is an integer and n >= 0
if n == 0:
return 1
child_result = F(n - 1)
return n * child_resultThe natural number measure decreases by one on every recursive call, so algorithm termination follows. For algorithm correctness, use mathematical induction: the zero base case returns ; assuming the child's answer is , the caller returns . This also explains why keeping the caller's matters.
There are exactly invocations and multiplications, including one invocation and no multiplications when . Ordinary execution of this recursive process uses at most active stack frames, hence frames for in Big O notation. If each test, call, subtraction and multiplication is counted as constant cost, its time complexity is . That is an arithmetic-operation model: exact arbitrary-length integer multiplication has growing cost, and neither the factorial output nor every stack frame's numeric contents occupies a universally fixed number of bits.
Keep an array unchanged, and sum entries in the half-open integer interval of array indices . The precondition requires integers and exact, terminating integer addition. An empty range returns the empty sum zero; a one-entry range returns that entry. Every longer range splits at its middle array index:For the original array , call . The left half returns , the right half returns , and the original invocation returns . The right half's left endpoint increases from zero to two: what decreases is range length , not every argument. Negative entries affect the answer but do not affect algorithm termination.
S(A, l, r):
require integer indices with 0 <= l <= r <= length(A)
size = r - l
if size == 0:
return 0
if size == 1:
return A[l]
middle = l + floor(size / 2)
left_sum = S(A, l, middle)
right_sum = S(A, middle, r)
return left_sum + right_sumSeven calls compute an array sum with only three frames active at once
. Original binary tree of invocations for , with integer intervals labeling ranges and upward arrows labeling returned sums. Small numbers give the order in which invocations begin when the left child runs first. The highlighted graph path contains the three active stack frames while the entry is read; the result from the completed left sibling is retained by its parent. Details.For range length , the children have lengths and , both positive and strictly less than . The floor function chooses the split; the ceiling function gives the other length. Algorithm termination follows by this natural number measure. For algorithm correctness, apply mathematical induction on : the two base cases return the specified sum; for a larger range, the two disjoint child ranges cover every original array index exactly once, so addition of their correct sums gives the required sum.
For , the invocation tree is a full binary tree with leaves, one per array entry. If is its number of nonleaf vertices, counting edges gives , so . Thus the total invocation count is , and there are combining additions. Here gives seven calls and three combining additions. For , there is one call and no combining addition; for , there is also one call and no combining addition, but no entry leaf, so the formula does not apply.
The call stack holds the active branch, rather than the entire invocation tree. Execute the left child completely before the right child, retaining the left result in the parent stack frame. The maximum number of active stack frames is for , and one for . Balanced splitting therefore needs frames for , compared with the frames of the factorial recursive process. Assuming constant-cost array access, index operations and addition, its time complexity is and its auxiliary space complexity is machine words for , excluding the stored input. Pass the same array with different endpoints, rather than copying slices. These bounds require all stored indices and partial sums to fit in a constant number of machine words; exact unbounded integer addition and storage require a separate bit cost analysis.
A base case and a decreasing natural number measure work together. Check that every invocation satisfies its precondition, each base case finishes with the correct output, and every other invocation makes finitely many recursive calls with strictly smaller measure. All local work must also terminate. By well-founded induction, the children finish, so their caller finishes; if their answers are correct and the combination rule preserves the postcondition, the caller is correct too. This proves total correctness, not just correctness conditional on return.
Strict decrease without a lower bound is insufficient: subtracting one forever from a negative integer never reaches zero. Even a positive real-valued measure can decrease indefinitely, as shows. A well-founded relation rules out that descent. In structural recursion, a proper child subtree of a finite binary tree supplies progress without numeric arguments. The proof obligation is the relation between parent and child instances, together with terminating local work and complete base cases.
A case answered without further recursive calls. Complete base cases are one part of an algorithm termination argument; the other cases must progress in a well-founded relation.
An invocation made by a recursive procedure of itself, directly or through another procedure. Each invocation has its own arguments and local variables; a returning invocation supplies an output to its caller.
Articles by others on the same topic
Recursion in computer science is a programming technique where a function calls itself directly or indirectly to solve a problem. It is commonly used to solve problems that can be broken down into smaller subproblems of the same type. ### Key Components of Recursion: 1. **Base Case**: This is a condition that stops the recursion. It defines the simplest instance of the problem that can be solved without further recursion.

