Update
This commit is contained in:
parent
165d7890e6
commit
bb467bc532
20 changed files with 1996 additions and 1978 deletions
|
@ -6,7 +6,7 @@ Recursion (from Latin recursio, "running back") in general is a situation in whi
|
|||
|
||||
{ Perhaps an analogy to this kind of recursion may be an "Inception"-style multi level dreams: imagine having a dream in a dream in a dream ... and so on -- and then at one point you start waking up, always getting back to where you were in each of the dreams, and so on until you completely wake up. --drummyfish }
|
||||
|
||||
We divide recursion to a **direct** and **indirect** one. In direct recursion the function calls itself directly, in indirect function *A* calls a function *B* which ends up (even possibly by calling some more functions) calling *A* again. Indirect recursion is tricky because it may appear by mistake and cause a [bug](bug.md) (which is nevertheless easily noticed as the program will mostly run out of memory and crash).
|
||||
We subdivide recursion to a **direct** and **indirect**. In direct recursion the function calls itself directly, in indirect function *A* calls a function *B* which ends up (even possibly by calling some more functions) calling *A* again. Indirect recursion is tricky because it may appear by mistake and cause a [bug](bug.md) (which is nevertheless easily noticed as the program will mostly run out of memory and crash).
|
||||
|
||||
When a function calls itself, it starts "diving" deeper and deeper and in most situations we want this to stop at some point, so in most cases **a recursion has to contain a terminating condition**. Without this condition the recursion will keep recurring and end up in an equivalent of an infinite loop (which in case of recursion will however crash the program with a [stack overflow](stack_overflow.md) exception). Let's see this on perhaps the most typical example of using recursion, a [factorial](factorial.md) function:
|
||||
|
||||
|
@ -60,7 +60,7 @@ unsigned int factorial(unsigned int x)
|
|||
}
|
||||
```
|
||||
|
||||
Here is another example of elegant recursion: printing string backwards:
|
||||
Printing string backwards also exemplifies elegant recursion:
|
||||
|
||||
```
|
||||
#include <stdio.h>
|
||||
|
@ -102,8 +102,8 @@ readAndPrintBackwards
|
|||
|
||||
Some problems, for example [Ackermann function](ackermann_function.md), [quick sort](quick_sort.md), [tree](tree.md) traversals or the mentioned factorial are said to be "recursive" because they are just most elegantly defined and/or solved with recursion, but as we've seen, there is no problem that would inherently require recursive function calls. There may exist Turing complete languages without recursion that can still solve all problems that any other language can.
|
||||
|
||||
How do the computers practically make recursion happen? Basically they use a [stack](stack.md) to remember states (such as values of local variables and return addresses) on each level of the recursive dive -- each such state is captured by so called **stack frame**. In programming languages that support recursive function calls this is hidden behind the scenes in the form of so called **[call stack](call_stack.md)**. This is why an infinite recursion causes stack overflow.
|
||||
How do computers practically make recursion happen? Basically they use a [stack](stack.md) to remember states (such as values of local variables and return addresses) on each level of the recursive dive -- each such state is captured by so called **stack frame**. In programming languages that support recursive function calls this is hidden behind the curtains in the form of so called **[call stack](call_stack.md)**. This is why an infinite recursion causes stack overflow whereas infinite loop doesn't -- each recursive call creates a new stack frame in the call stack and at one point the stack overflows.
|
||||
|
||||
Another important type of recursion is **tail recursion** which happens when the recursive call in a function is the very last command. It is utilized in functional languages that use recursion instead of loops. This kind of recursion can be optimized by the compiler into basically the same code a loop would produce, so that e.g. stack won't grow tremendously.
|
||||
Another relevant type of recursion is **tail recursion** that occurs when the recursive call in a function is the very last command. It is utilized in functional languages that use recursion instead of loops. This kind of recursion can be optimized by the compiler into basically the same code a loop would produce, so that e.g. stack won't grow tremendously.
|
||||
|
||||
Mathematical recursive functions find use in [computability](computability.md) theory where they help us (similarly to e.g. [Turing machines](turing_machine.md)) define [classes](class.md) of functions (such as primitive recursive and partial recursive) by how "computationally strong" of a computer we need to compute them.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue