vault backup: 2023-11-13 13:50:53
This commit is contained in:
153
Algo/B1/Séminaire/Chapter 5 - Recursivity.md
Normal file
153
Algo/B1/Séminaire/Chapter 5 - Recursivity.md
Normal file
@ -0,0 +1,153 @@
|
||||
|
||||
<center><img src="https://gitea.louisgallet.fr/lgallet/epicours/raw/branch/main/Algo/S%C3%A9minaire/assets/recursivite-meme.png " width=512 height=auto /> </center>
|
||||
|
||||
### 5.1. Simple functions
|
||||
To create a recursive function we have to use this structure
|
||||
|
||||
```Ocaml
|
||||
(*normal function*)
|
||||
# let f = expr -> 1) evaluate expr ; 2) create & link f to the result
|
||||
|
||||
(*recursiv function*)
|
||||
# let rec f = expr -> 1) create f ; 2) evaluate expr ; 3) link f to the result
|
||||
```
|
||||
|
||||
**Exmple with factorial function**
|
||||
```Ocaml
|
||||
# let rec fact = function
|
||||
| 0 -> 1
|
||||
| n -> n * fact(n-1)
|
||||
|
||||
# fact 4;;
|
||||
-: int = 24
|
||||
```
|
||||

|
||||
> ⚠️ CAML have a call stack limite (it will block with stack overflow if the limit is reach)
|
||||
|
||||
**Basic expression**
|
||||
```Ocaml
|
||||
let rec f params =
|
||||
if stop condition then
|
||||
stop expression
|
||||
else
|
||||
recursive expression
|
||||
```
|
||||
|
||||
To write a recurvise function we need two things
|
||||
1) There always is a stop case
|
||||
2) The parameters of a recursive call are different then its parent call, and go towards the stop condition
|
||||
|
||||
### 5.2. Down
|
||||
```Ocaml
|
||||
# let rec countdown n =
|
||||
if n < 0 then
|
||||
()
|
||||
else
|
||||
begin
|
||||
print_int n ;
|
||||
print_newline();
|
||||
countdown(n-1);
|
||||
end;;
|
||||
val countdown = int -> unit = ()
|
||||
|
||||
# countdown 3;;
|
||||
3
|
||||
2
|
||||
1
|
||||
- : unit = ()
|
||||
```
|
||||
Flowchart of CAML evaluation
|
||||
```mermaid
|
||||
flowchart LR
|
||||
|
||||
A[ctd 3] --> B[ctd 2] --> C[ctd 1] --> D[ctd 0] --> E[ctd -1] --> F[ ] --> E --> D --> C --> B --> A
|
||||
```
|
||||
> ctd is countdown
|
||||
|
||||
## 5.3. Several recursive calls
|
||||
A function that have several recursive calls is defined like this
|
||||
$$
|
||||
Fn = {1 -> \text{if } n\eqslantless{1} \brace{Fn+1+Fn+2} }
|
||||
$$
|
||||
**Fibonacci functions**
|
||||
```Ocaml
|
||||
let rec fibonacci n =
|
||||
if n = 0 then
|
||||
0
|
||||
else if n = 1 then
|
||||
1
|
||||
else
|
||||
fibonacci(n-1) + fibonacci(n-2);;
|
||||
|
||||
let rec odd n =
|
||||
if n = 0 then
|
||||
false
|
||||
else
|
||||
even (n-1);;
|
||||
|
||||
and even n =
|
||||
if n = 0 then
|
||||
true
|
||||
else
|
||||
add (n-1);;
|
||||
val add : int -> bool = <fun>
|
||||
val even : int -> bool = <fun>
|
||||
```
|
||||
|
||||
An accumulator is a variable used to stock temporary the intermediaries results of a recursive operation. In CAML the syntax for the accumulator (`inv`) is: (exemple with reverse_int exercise. See 4.9 - b)
|
||||
```Ocaml
|
||||
# let reverse_int =
|
||||
let rec rev inv = function
|
||||
| 0 -> inv
|
||||
| n -> rev (inv*10 + n mod 10)(n/10)
|
||||
in rev 0 n;;
|
||||
```
|
||||
|
||||
## 4.3. Complexity
|
||||
Exemple with egypt (4.10) vs multiply (4.6):
|
||||
```Ocaml
|
||||
# let multiply a b =
|
||||
let (a,b) = if a > b then
|
||||
(a,b) else
|
||||
(b,a)
|
||||
in let rec mult = function
|
||||
| 0 -> 0
|
||||
| b -> a +mult (b-1)
|
||||
in mult b;;
|
||||
```
|
||||
|
||||
The best algorithm in term of complexity is the parameter that is constant/linear or logarithmic. If you have an exponential algorithm, you can put it in trash :)
|
||||
|
||||
**Exemple with fibonacci algorithm**
|
||||
```Ocaml
|
||||
# let rec fibo = function
|
||||
0|1 -> 1
|
||||
| n -> fibo (n-1) + fibo(n-2);;
|
||||
```
|
||||
|
||||
|
||||
| |res|how (for human) ?|How (for function) ?|
|
||||
|:----:|:----:|:----:|:----:|
|
||||
|0|1|def|1 call|
|
||||
|1|1|def|1 call|
|
||||
|2|2|+|3 calls|
|
||||
|3|3|+|5 calls|
|
||||
|4|5|+|9 calls|
|
||||
|5|8|+|15 calls|
|
||||
|6|13|+|14 calls|
|
||||
| | |$0(n)$|$O(2^n)$|
|
||||
|
||||
|
||||
<center><img src="https://imgur.com/6OWREOm.png" height=400 width=auto/></center>
|
||||
|
||||
This function is not optimize because the number of calls is growing exponentially.
|
||||
A good function will be:
|
||||
```Ocaml
|
||||
# let fibo n =
|
||||
let rec fib i fi fi_1 =
|
||||
if n <= i then
|
||||
fi
|
||||
else
|
||||
fib (i+1)(fi+fi_1)fi
|
||||
in fib 1 1 1
|
||||
```
|
Reference in New Issue
Block a user