Nu obții 100 de puncte sau ai nelămuriri în privința problemelor? Scrie-mi pe Instagram.
Ai găsit o greșeală, vrei să raportezi un utilizator sau vrei să comunici altceva? Folosește formularul de contact.
Vrei să ne transmiți o părere despre platformă? Folosește formularul de feedback.
Folosește următoarele shortcuturi pentru a naviga mai ușor pe platformă.
Meniu shortcuturi | ? |
Căutare probleme sau utilizatori | / |
Navigare printre rezultatele căutării | ↑, ↓ |
Meniu de contact și feedback | CTRL + Shift + F |
Ieșire din meniuri | Esc |
Setări editor | CTRL + Shift + S |
Schimbare stil editor | CTRL + Shift + E |
Șabloane de cod | CTRL + Shift + 1/2/3 |
Golire editor | CTRL + Shift + 4 |
Să ne gândim la un copac: acesta are ramuri, fiecare ramură având la rândul ei mai multe ramuri mai mici, și așa mai departe până la cele mai mici ramuri.
În matematică și în informatică întâlnim o noțiune similară, numită recursivitate (sau recurență), de a defini ceva cu ea însăși.
Vom folosi funcții în această lecție — altfel, nu am putea să folosim recursivitatea.
Recursivitatea este proprietatea unui element de a se defini prin el însuși.
Noțiunea de recursivitate poate părea destul de dificil de înțeles, așadar să considerăm câteva exemple.
Factorialul unui număr n
, n!
, este egal cu produsul 1 × 2 × 3 × … × (n - 1) × n
. Putem să rescriem factorialul astfel: n! = (n - 1)! × n
. Astfel, am definit factorialul lui n
pe baza factorialului lui n - 1
.
Șirul Fibonacci este un șir cunoscut în matematică, cu primii doi termeni 1
și 1
, iar termenul F(n) = F(n - 1) + F(n - 2)
.
Progresiile aritmetice și geometrice se pot scrie recursiv: a(n) = a(n - 1) + r
, sau g(n) = g(n - 1) * r
.
Fractalii sunt un exemplu bun de recursivitate, în care nu există vreo limită de oprire (spre deosebire de șirul Fibonacci, spre exemplu, unde avem limita n = 1
sau n = 2
). Iată un fractal în formă de pătrat, în care colțul din stânga sus este identic cu tot pătratul:
Un alt fractal — triunghiul Sierpinski. Triunghiul se împarte în 4
triunghiuri egale, iar în cele 3
din colțuri se repetă fractalul.
Un ultim exemplu este efectul Droste: un ambalaj care se conține pe el însuși:
Să zicem că vrem să calculăm factorialul unui număr. Metoda clasică este următoarea:
#include <iostream>
using namespace std;
int factorial(int n) {
int fact = 1;
for(int i = 1; i <= n; i++) {
fact *= i;
}
return fact;
}
int main()
{
int n;
cin >> n;
cout << factorial(n);
return 0;
}
Dacă am implementa recursiv soluția la această problemă, am crea o funcție care se definește pe ea însăși în apel:
#include <iostream>
using namespace std;
int factorial(int n) {
if(n <= 0) { //Caz particular
return 1;
} else { //Formula generală
return n * factorial(n - 1);
}
}
int main()
{
int n;
cin >> n;
cout << factorial(n);
return 0;
}
Iată o reprezentare pentru apelarea factorial(4)
:
Variabilă / Expresie | Valoare |
---|---|
factorial(4) | ???4 * factorial(3)62424 |
factorial(3) | ???3 * factorial(2)266 |
factorial(2) | ???2 * factorial(1)122 |
factorial(1) | ???1 * factorial(0)111 |
factorial(0) | ???11 |
Recursivitatea aduce o nouă metodă de a vizualiza problemele. Această metodă, de a împărți problema curentă în probleme mai mici, până când ajungem la probleme simple și rezolvabile instant, va fi mai târziu (în clasa a XI-a) folosită la programarea dinamică.
Unele probleme sunt foarte greu — sau chiar imposibil — implementabile nerecursiv. În clasa a XI-a se vor folosi funcțiile recursive pentru backtracking.
Soluțiile recursive, fără optimizări, pot lua mai mult timp să ruleze, astfel că implementările recursive nu sunt foarte utile în programe în care viteza este importantă. Cu toate acestea, de obicei acest lucru nu reprezintă un pericol.
După cum s-a observat și anterior, majoritatea noțiunilor pe care le putem implementa recursiv (Fibonacci, progresii aritmetice sau geometrice, factorialul, etc.) s-au implementat deja nerecursiv. Așadar, nu are sens să reinventăm roata.
Completează următoarele secvențe de cod:
Să se determine recursiv al n
-lea termen tribonacci (elementul curent este egal cu suma ultimelor trei):
int tribo(int x) {
if(x <= 3) {
return 1;
}
??? tribo(x - 1) + tribo(x - ???) + tribo(x - 3);
}
Să se afișeze crescător primele n
numere naturale:
void f(int n) {
if(n > 1) {
???(n - 1);
}
cout << ??? << " ";
}