Ce vei învăța astăzi?
După această lecție vei scrie funcția recursivă a factorialului, vei explica mecanismul de executare prin stiva apelurilor și vei compara varianta recursivă cu cea iterativă.
Definiția factorialului
Definiție: Factorialul unui număr natural n, notat n!, este produsul numerelor de la 1 la n. Prin convenție, 0! = 1.
Definiția recursivă: factorial(n) = n * factorial(n - 1), cu cazul de bază factorial(0) = 1.
| n | n! | Calcul recursiv |
|---|---|---|
| 0 | 1 | cazul de bază |
| 1 | 1 | 1 · factorial(0) = 1 · 1 |
| 2 | 2 | 2 · factorial(1) = 2 · 1 |
| 3 | 6 | 3 · factorial(2) = 3 · 2 |
| 4 | 24 | 4 · factorial(3) = 4 · 6 |
Funcția factorial recursivă în C++
#include <iostream>
using namespace std;
long long factorial(int n)
{
if (n == 0)
return 1;
return n * factorial(n - 1);
}
int main()
{
int n;
cout << "n = ";
cin >> n;
cout << factorial(n);
return 0;
}
Stiva apelurilor pentru factorial(4)
Comparație cu varianta iterativă
#include <iostream>
using namespace std;
int main()
{
int n;
long long f = 1;
cin >> n;
for (int i = 2; i <= n; i++)
f = f * i;
cout << f;
return 0;
}
De reținut
- Ambele variante dau același rezultat; recursivitatea folosește stiva, iar iterația folosește o variabilă.
- Pentru n mare, factorialul crește foarte repede; folosim
long long. - Cazul de bază este esențial: fără el, funcția se apelează la nesfârșit.
Exercițiu de completare
Completează enunțul despre factorial cu cuvintele potrivite:
Factorialul unui număr natural n, notat ______, este produsul numerelor de la 1 la n. Prin convenție, ______ = 1, care reprezintă ______. Pentru n > 0, n! = n · ______, numit pas ______.
Bancă de cuvinte:
Exercițiu de completare
Completează funcția factorial din codul C++ de mai jos:
Bancă de cuvinte:
Test de înțelegere
Test rapid - factorial:
1. Cazul de bază pentru factorial este:
2. factorial(3) are valoarea:
3. În stiva apelurilor, primul apel efectuat este:
Aprofundare
Creșterea rapidă și depășirea tipului de date. Factorialul crește extrem de repede: 10! = 3.628.800, 13! = 6.227.020.800 (depășește int), iar 20! ≈ 2,43 × 10⁸, valoare care depășește și long long. Din acest motiv, funcția factorial trebuie declarată cu tipul de return long long și folosită cu prudență pentru valori mari ale lui n.
Adâncimea recursivității. Pentru n mic (de exemplu 20), stiva suportă fără probleme cei 20 de apeluri impuse. Pentru valori foarte mari, însă, numărul de apeluri poate umple stiva; varianta iterativă cu buclă for nu are această problemă și este de preferat când performanța și siguranța sunt importante.
Cazuri particulare.
factorial(0) = 1prin convenție matematică: produsul gol este 1, exact cazul de bază.factorial(1) = 1; pentrun = 1funcția poate returna direct 1, dar apelulfactorial(0)este și el corect.- Ordinea înmulțirii
n * factorial(n - 1)este identică cufactorial(n - 1) * n, dar prima formă este mai ușor de urmărit pe stivă. - Pentru
nnegativ, funcția ar intra în recursie infinită; validarea intrării evită această problemă.
PbInfo - Factorial
Enunț:
Cerință: Se citește un număr natural n. Să se afișeze n! (factorialul lui n), folosind un subprogram recursiv.
Date de intrare:
Programul citește de la tastatură numărul natural n.
Date de ieșire:
Programul va afișa pe ecran valoarea n!.
Restricții și precizări:
0 ≤ n ≤ 20. Rezultatul încape într-un număr de tip long long.
Exemplu:
Intrare:
5
Ieșire:
120
Cum gândim soluția:
- Definim funcția
factorial(n)care întoarcelong long - Cazul de bază: dacă
n == 0, întoarcem 1 - Altfel întoarcem
n * factorial(n - 1) - În main citim n și afișăm
factorial(n)
Scrie soluția în C++:
Soluție corectă:
#include <iostream>
using namespace std;
long long factorial(int n)
{
if (n == 0)
return 1;
return n * factorial(n - 1);
}
int main()
{
int n;
cin >> n;
cout << factorial(n);
return 0;
}
Ce învățăm: cazul de bază 0! = 1 oprește recurența, iar rezultatul se construiește la urcarea pe stivă.
PbInfo - Suma factorialelor
Enunț:
Cerință: Se citește un număr natural n. Să se calculeze suma 1! + 2! + ... + n!, folosind un subprogram recursiv pentru factorial.
Date de intrare:
Programul citește de la tastatură numărul natural n.
Date de ieșire:
Programul va afișa pe ecran suma factorialelor.
Restricții și precizări:
1 ≤ n ≤ 20. Rezultatul poate fi mare, folosiți tipul long long.
Exemplu:
Intrare:
4
Ieșire:
33
Cum gândim soluția:
- Definim funcția recursivă
factorial(n) - În main parcurgem cu o buclă de la 1 la n
- Adunăm la suma s valoarea
factorial(i) - Afișăm suma
Scrie soluția în C++:
Soluție corectă:
#include <iostream>
using namespace std;
long long factorial(int n)
{
if (n == 0)
return 1;
return n * factorial(n - 1);
}
int main()
{
int n;
long long s = 0;
cin >> n;
for (int i = 1; i <= n; i++)
s = s + factorial(i);
cout << s;
return 0;
}
Ce învățăm: un subprogram recursiv poate fi apelat de mai multe ori, din interiorul unei bucle, pentru a calcula o sumă.
Exercițiul Practic: Factorialul în practică
Sarcini de lucru
Rezolvă sarcinile următoare pentru a stăpâni factorialul recursiv
Sarcina 1: Program cu factorial
Cerință: Scrie un program C++ care citește n și afișează pe ecran valoarea n! folosind o funcție recursivă. Testează pentru n = 6 (rezultatul trebuie să fie 720).
Soluție pentru Sarcina 1:
#include <iostream>
using namespace std;
long long factorial(int n)
{
if (n == 0)
return 1;
return n * factorial(n - 1);
}
int main()
{
int n;
cin >> n;
cout << factorial(n);
return 0;
}
Verifică: pentru n = 6, factorial(6) = 720.
Sarcina 2: Stiva apelurilor
Cerință: Scrie pe foaie (sau în căsuța de mai jos) secvența apelurilor pentru factorial(5), apoi valorile întoarse la fiecare urcare pe stivă.
Soluție pentru Sarcina 2:
Coborâre: factorial(5), factorial(4), factorial(3), factorial(2), factorial(1), factorial(0) - caz de bază Urcare: factorial(0) = 1 factorial(1) = 1 * 1 = 1 factorial(2) = 2 * 1 = 2 factorial(3) = 3 * 2 = 6 factorial(4) = 4 * 6 = 24 factorial(5) = 5 * 24 = 120