The code for this lecture is available in this archive (first parts) and this one (listing files and folders recursively).
Introduction
Recursion is a central notion in programming, simple to state but difficult to master: a method is recursive if it calls itself. This concept is related to the idea of repetition, or looping, of program parts, and come with the same danger of not terminating. Below, we present some simple recursive programs: while some could be written without recursion, some would be very hard, if possible at all, to write without using recursion.
First Examples
Consider the following:
If we call displayAll(3);
, then the following will happen:
displayAll(3)
will test that3>0
,displayAll(3)
will display “3 ”,displayAll(3)
will calldisplayAll(2)
,displayAll(2)
will test that2>0
,displayAll(2)
will display “2 ”,displayAll(2)
will calldisplayAll(1)
,displayAll(1)
will test that1>0
,displayAll(1)
will display “1 ”,displayAll(1)
will calldisplayAll(0)
,displayAll(0)
will test that0>0
,displayAll(0)
will terminate.
displayAll(1)
will terminate.
displayAll(2)
will terminate.
displayAll(3)
will terminate.
Hence, displayAll
calls itself with a smaller number, unless that
number is 0, in which case it simply terminates. In our example, it
would display “3 2 1 “.
When the function calls itself matters a lot. Indeed, consider
displayRAll
, which calls itself before executing the
Console.WriteLine
instruction:
If we call displayRall(3);
, then the following will happen:
displayRall(3)
will test that3>0
,displayRall(3)
will calldisplayRall(2)
,displayRall(2)
will test that2>0
,displayRall(2)
will calldisplayRall(1)
,displayRall(1)
will test that1>0
,displayRall(1)
will calldisplayRall(0)
,displayRall(0)
will test that0>0
,displayRall(0)
will terminate.
displayRall(1)
will display “1 ”,displayRall(1)
will terminate.
displayRall(2)
will display “2 ”,displayRall(2)
will terminate.
displayRall(3)
will display “3 ”,displayRall(3)
will terminate.
In this example, “1 2 3 ” would be displayed: the order is reversed with
respect to displayAll
!
❗ Caution |
---|
Recursion can be very powerful and can very easily make your program crash or misbehave. To see it for yourself, after saving all important documents, replace - with + in the previous examples and run the programs again. |
displayAll
is an example of tail recursion: the recursive call is
the last statement in the method. displayRAll
is an example of
head recursion: the recursive call is the first statement in the
method. They are furthormore both examples of linear recursion, as
they call themselves only once.
Recursive Methods Returning a Value
Recursive methods can also return a value, used by previous calls to compute some other value.
Multiplication
For example, consider that multiplication can be defined by addition: indeed, is where is summed times. Stated differently (read: recursively), is . We can implement such a program easily:
For example, mult(2, 10)
tests that 2
is neither 0 nor 1, and adds
10 with the result of mult(1, 10)
, which is 10 since the first
argument is 1.
Observe that mult(10000000, 0)
would call mult
10000001 times and
add 0 to itself 10000001 times: this algorithm is not very efficient!
Factorial
The factorial of is . This function can easily be implemented using recursion:
Note that this code actually compute e.g., (with one superfluous ): can you see why?
Listing Files and Directories — Recursively {#listing-files-and-directories-recursively}
While multiplication and factorial can be implemented without recursion, some structures makes it natural, or even required, to use recursion. Going through folders and files is an example of such situation.
Note that our previous examples were calling themselves only once per
method call, but that ListDir
calls itself as many times as there are
folders in the folder currently examined.