Definiția vectorului
Definiție: Un vector (array) este o structură de date care stochează o colecție de elemente de același tip, în locații consecutive de memorie. Fiecare element poate fi accesat direct printr-un indice.
Vectorii sunt folosiți pentru a gestiona ușor colecții de date, cum ar fi notele elevilor, temperaturile dintr-o săptămână, sau orice listă de valori de același tip.
Declararea vectorilor
tip nume[dimensiune];
unde:
- tip - tipul de date al elementelor (int, float, char, bool etc.)
- nume - identificatorul vectorului
- dimensiune - numărul de elemente (trebuie să fie o constantă)
int note[30]; // vector de 30 de numere întregi float temperaturi[7]; // vector de 7 numere reale char litere[26]; // vector de 26 de caractere bool rezultate[100]; // vector de 100 de valori boolene
Declararea cu vector din STL (alternativă)
Pe lângă vectorii clasici (C-style), în C++ putem folosi și vector<int> din biblioteca standard (STL). Aceasta este o alternativă modernă și flexibilă.
// Declarare cu dimensiune fixă de 20 de elemente (toate inițializate cu 0) vector<int> v(20); // Declarare fără dimensiune (vector gol, se adaugă elemente cu push_back) vector<int> v; v.push_back(5); // adaugă 5 la sfârșit
vector<int> v(n) creează n locuri deja pregătite, pe când vector<int> v; începe gol și trebuie umplut cu push_back.
int v; declară o singură variabilă de tip int, NU un vector! Ca să ai un vector, trebuie neapărat să folosești paranteze pătrate int v[20]; sau STL: vector<int> v(20);. Fără paranteze sau dimensiune, nu poți accesa „căsuțe" cu v[i].
Indexarea vectorilor
Regula fundamentală: În C++, indexarea începe de la 0. Primul element are indicele 0, iar ultimul are indicele dimensiune-1.
int v[5] = {10, 20, 30, 40, 50};
// v[0] = 10 (primul element)
// v[1] = 20
// v[2] = 30
// v[3] = 40
// v[4] = 50 (ultimul element)
// v[5] - ERORĂ! depășirea limitei vectorului
Inițializarea vectorilor
Putem inițializa un vector chiar la declarare, folosind acolade.
// 1. Inițializare completă
int a[5] = {10, 20, 30, 40, 50};
// 2. Inițializare parțială (restul devin 0)
int b[10] = {1, 2, 3}; // b[0]=1, b[1]=2, b[2]=3, b[3]...b[9]=0
// 3. Fără dimensiune explicită (compilatorul numără)
int c[] = {2, 4, 6, 8}; // dimensiunea este 4
// 4. Toate elementele cu aceeași valoare
int d[100] = {0}; // toate elementele sunt 0
int v[5];
v = {1, 2, 3, 4, 5}; // ❌ GREȘIT!
Citirea și afișarea unui vector
De obicei, citim mai întâi numărul de elemente (n), apoi elementele propriu-zise, folosind o buclă for.
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
const int MAX = 1000;
int v[MAX];
// Citire
for (int i = 0; i < n; i++) {
cin >> v[i];
}
// Afișare
for (int i = 0; i < n; i++) {
cout << v[i] << " ";
}
return 0;
}
Pregătire test - Ora 17
- Adevărat sau Fals? Pot declara un singur vector care să conțină și note (numere) și numele elevilor (litere) în același timp.
Fals — vectorul stochează elemente de același tip.
- Adevărat sau Fals? Într-un vector cu 5 elemente, primul element se accesează cu
v[0], nu cuv[1].Adevărat — indexarea începe de la 0. - Adevărat sau Fals? Linia de cod
int x;creează o singură variabilă, nu un tablou de valori, deci nu pot scriex[2].Adevărat —int x;este o variabilă simplă, nu un vector. - Adevărat sau Fals? Dacă am declarat
int v[5];pe o linie, pot scrie mai târziuv = {10, 20, 30, 40, 50};și funcționează.Fals — atribuirea cu acolade funcționează doar la declarare. - Alegere multiplă: Care dintre următoarele creează corect un loc pentru 20 de numere întregi?
a)numbers: array;
b)int numbers;
c)vector<int> numbers(20);c) vector<int> numbers(20); - Alegere multiplă: Vrem un vector de 100 de elemente, toate cu valoarea 0 din start. Care declarare este corectă?
a)int v = {0};
b)v = 0;
c)int v[100] = {0};c) int v[100] = {0}; - Completează: Datele dintr-un vector sunt stocate în memorie în locații _______, una după alta.
consecutive
- Completează: Valoarea numerică prin care accesăm un anumit element al vectorului se numește _______.
indice
- Completează: Un vector declarat cu 8 căsuțe are poziții de la 0 la _______.
7
- Completează: Dacă vreau să stochez caractere (litere) într-un vector, folosesc tipul de date _______.
char
Ce înseamnă parcurgerea unui vector?
Definiție: Parcurgerea unui vector înseamnă vizitarea fiecărui element al acestuia, de obicei pentru a efectua o operație (citire, afișare, modificare, calcul).
Parcurgerea cu instrucțiunea for (crescător)
Este cea mai folosită metodă. Indexul pornește de la 0 și crește până la n-1.
for (int i = 0; i < n; i++) {
// aici lucrăm cu v[i]
}
Exemplu: afișare elemente
Parcurgerea cu instrucțiunea while
Este similară, dar necesită inițializarea și incrementarea manuală a contorului.
int i = 0;
while (i < n) {
// lucrăm cu v[i]
i++; // FOARTE IMPORTANT! Altfel buclă infinită
}
i++, bucla va rula la nesfârșit.
Parcurgerea inversă (descrescător)
Pentru a parcurge vectorul de la ultimul element la primul, folosim un for descrescător.
for (int i = n - 1; i >= 0; i--) {
cout << v[i] << " ";
}
// ATENȚIE: i >= 0, nu i > 0! Altfel nu mai afișezi v[0]
Modificarea elementelor în timpul parcurgerii
Putem schimba valorile din vector în aceeași buclă.
// Dublăm toate elementele
for (int i = 0; i < n; i++) {
v[i] = v[i] * 2; // sau v[i] *= 2;
}
// Ridicăm la pătrat elementele de pe poziții pare
for (int i = 0; i < n; i += 2) {
v[i] = v[i] * v[i];
}
// Transformăm negativele în pozitive
for (int i = 0; i < n; i++) {
if (v[i] < 0) {
v[i] = -v[i];
}
}
Operații pe toate elementele
De multe ori parcurgem vectorul pentru a calcula ceva, cum ar fi suma sau numărul de elemente care îndeplinesc o condiție.
// Suma elementelor
int suma = 0;
for (int i = 0; i < n; i++) {
suma += v[i];
}
// Numărul elementelor pare
int cntPare = 0;
for (int i = 0; i < n; i++) {
if (v[i] % 2 == 0) {
cntPare++;
}
}
| Tip parcurgere | Cod corect | Greșeală frecventă |
|---|---|---|
| Crescătoare | for(i=0; i<n; i++) |
for(i=1; i<=n; i++) - sare peste v[0] și accesează v[n] |
| Inversă | for(i=n-1; i>=0; i--) |
for(i=n-1; i>0; i--) - nu afișează v[0] |
| Cu while | i=0; while(i<n) { ... i++; } |
while(i<n) { ... } - buclă infinită |
Pregătire test - Ora 18
- Alegere multiplă: Vrem să afișăm elementele unui vector de la ultimul la primul. Care for este corect?
a)for(int i=n; i>0; i--)
b)for(int i=n-1; i>=0; i--)
c)for(int i=0; i<n; i++)b) for(int i=n-1; i>=0; i--) - Alegere multiplă: Avem codul:
while(i<n) { cout << v[i]; }. Ce problemă are?
a) Lipseștecin
b) Lipseștei++
c) Vectorul nu are acoladeb) Lipsește i++ — fără el, bucla rulează la infinit.
Definiții
Minimul unui vector este cea mai mică valoare dintre elementele sale.
Maximul unui vector este cea mai mare valoare dintre elementele sale.
Algoritmul pentru găsirea minimului
- Inițializăm variabila
mincu primul element al vectorului (v[0]). - Parcurgem vectorul de la al doilea element (i=1) până la sfârșit.
- Pentru fiecare element, dacă este mai mic decât
min, actualizămmin.
int min = v[0];
for (int i = 1; i < n; i++) {
if (v[i] < min) {
min = v[i];
}
}
Algoritmul pentru găsirea maximului
Similar, dar comparăm cu operatorul >.
int max = v[0];
for (int i = 1; i < n; i++) {
if (v[i] > max) {
max = v[i];
}
}
Găsirea simultană a minimului și maximului
Putem găsi ambele valori într-o singură parcurgere, ceea ce este mai eficient.
int min = v[0], max = v[0];
for (int i = 1; i < n; i++) {
if (v[i] < min) min = v[i];
if (v[i] > max) max = v[i];
}
Determinarea poziției (prima apariție)
Pentru a afla pe ce poziție apare minimul (sau maximul) pentru prima dată, păstrăm și un index.
int min = v[0];
int pozMin = 0;
for (int i = 1; i < n; i++) {
if (v[i] < min) {
min = v[i];
pozMin = i;
}
}
cout << "Minimul " << min << " apare prima dată la poziția " << pozMin;
Determinarea tuturor aparițiilor minimului
Mai întâi găsim valoarea minimă, apoi parcurgem din nou și afișăm toate pozițiile unde apare.
// Găsim minimul
int min = v[0];
for (int i = 1; i < n; i++) {
if (v[i] < min) min = v[i];
}
// Afișăm toate pozițiile
cout << "Minimul apare la pozițiile: ";
for (int i = 0; i < n; i++) {
if (v[i] == min) {
cout << i << " ";
}
}
min cu 0 sau cu o valoare arbitrară! De exemplu, dacă toate numerele sunt pozitive și inițializezi min cu 0, minimul va rămâne 0 (greșit). Folosește întotdeauna v[0].
Exemplu: găsire minim pentru v = [8, 3, 10, 2, 7]
Pregătire test - Ora 19
- Adevărat sau Fals? Când căutăm cel mai mare element dintr-un vector, cel mai sigur mod este să presupunem inițial că elementul de pe prima poziție (
v[0]) este cel mai mare.Adevărat — inițializăm max cu v[0]. - Alegere multiplă: Vrem să aflăm pe ce poziție se află cea mai mică valoare dintr-un vector. Ce informație trebuie să salvăm pe parcurs?
a) Indicele (poziția)
b) Suma tuturor elementelor
c) Doar valoarea minimăa) Indicele (poziția)
Ce este un flag?
Flag (steguleț) = o variabilă de tip boolean (bool) sau int cu valori 0/1 care reține dacă o anumită proprietate este îndeplinită pentru elementele vectorului. Funcționează ca un „beculeț" — aprins (true) sau stins (false) — care ne spune dacă am găsit sau nu ceea ce căutam.
Tipul de date bool
bool este tipul de date care poate reține doar două valori: true (adevărat) sau false (fals). Este folosit pentru flag-uri, condiții și orice situație în care avem nevoie de un răspuns de tip da/nu.
bool gasit = false; // inițial nu am găsit nimic bool esteValid = true; // presupunem că e valid
1. Verificarea "toate elementele au proprietatea P"
Pornim cu flag-ul true și îl facem false dacă găsim un contraexemplu.
bool toatePare = true; // presupunem că toate sunt pare
for (int i = 0; i < n; i++) {
if (v[i] % 2 != 0) { // dacă găsim un element impar
toatePare = false;
break; // ieșim din buclă (optimizare)
}
}
if (toatePare) {
cout << "Toate elementele sunt pare";
} else {
cout << "Nu toate sunt pare";
}
2. Verificarea "există cel puțin un element cu proprietatea P"
Pornim cu flag-ul false și îl facem true dacă găsim un exemplu.
bool existaPar = false;
for (int i = 0; i < n; i++) {
if (v[i] % 2 == 0) {
existaPar = true;
break;
}
}
3. Verificarea "niciun element nu are proprietatea P"
Pornim cu flag-ul true și îl facem false dacă găsim un contraexemplu.
bool niciunNegativ = true;
for (int i = 0; i < n; i++) {
if (v[i] < 0) {
niciunNegativ = false;
break;
}
}
| Întrebare | Flag inițial | Ce căutăm | Când schimbăm flag-ul |
|---|---|---|---|
| Toate elementele au P? | true | un element care NU are P | îl facem false |
| Există un element cu P? | false | un element care ARE P | îl facem true |
| Niciun element nu are P? | true | un element care ARE P | îl facem false |
4. Verificări cu proprietăți complexe
Pentru proprietăți precum "număr prim" sau "număr perfect", definim funcții separate.
// Funcție care verifică dacă un număr este prim
bool estePrim(int x) {
if (x < 2) return false;
for (int d = 2; d * d <= x; d++) {
if (x % d == 0) return false;
}
return true;
}
// Verificăm dacă toate elementele sunt prime
bool toatePrime = true;
for (int i = 0; i < n; i++) {
if (!estePrim(v[i])) {
toatePrime = false;
break;
}
}
// Verificăm dacă există numere prime
bool existaPrim = false;
for (int i = 0; i < n; i++) {
if (estePrim(v[i])) {
existaPrim = true;
break;
}
}
Pregătire test - Ora 20
- Adevărat sau Fals? O variabilă flag funcționează ca un comutator — poate fi doar „da" sau „nu" — și o folosim pentru a ține minte dacă am descoperit ceva anume în vector.
Adevărat — flag-ul e ca un beculeț: aprins (true) sau stins (false).
- Adevărat sau Fals? Poziția unui element în vector (indicele) și valoarea stocată pe acea poziție reprezintă întotdeauna același număr.
Fals — indicele (i) arată UNDE ești, valoarea (v[i]) arată CE este acolo.
- Alegere multiplă: Vrem să verificăm dacă în vector se află măcar un număr divisibil cu 2. Cu ce pornim variabila flag?
a)0
b)true
c)falsec) false — pentru „există", pornim cu false și căutăm un exemplu. - Completează: Tipul de variabilă care stochează exclusiv două stări (adevărat sau fals) se numește _______.
bool
Ce înseamnă numărarea?
Numărarea elementelor înseamnă parcurgerea vectorului și creșterea unui contor de fiecare dată când un element îndeplinește o condiție specificată.
Modelul general al numărării
int cnt = 0; // contorul pornește de la 0
for (int i = 0; i < n; i++) {
if (condiție(v[i])) {
cnt++; // creștem contorul
}
}
cout << cnt;
Exemple de numărare
int cntPare = 0, cntImpare = 0;
for (int i = 0; i < n; i++) {
if (v[i] % 2 == 0) {
cntPare++;
} else {
cntImpare++;
}
}
int cntPoz = 0, cntNeg = 0, cntZero = 0;
for (int i = 0; i < n; i++) {
if (v[i] > 0) {
cntPoz++;
} else if (v[i] < 0) {
cntNeg++;
} else {
cntZero++;
}
}
Numărarea în interval [a, b]
int a, b;
cin >> a >> b;
int cnt = 0;
for (int i = 0; i < n; i++) {
if (v[i] >= a && v[i] <= b) {
cnt++;
}
}
Numărarea aparițiilor unei anumite valori
int x;
cin >> x;
int cnt = 0;
for (int i = 0; i < n; i++) {
if (v[i] == x) {
cnt++;
}
}
Numărarea cu condiții compuse (AND, OR)
// Numără elementele pozitive și pare
int cnt = 0;
for (int i = 0; i < n; i++) {
if (v[i] > 0 && v[i] % 2 == 0) {
cnt++;
}
}
// Numără elementele care sunt zero sau negative
int cnt2 = 0;
for (int i = 0; i < n; i++) {
if (v[i] <= 0) { // <= 0 înseamnă negativ sau zero
cnt2++;
}
}
if (i % 2 == 0) numără pozițiile pare, nu valorile pare. Pentru valori pare folosim if (v[i] % 2 == 0).
Pregătire test - Ora 21
- Adevărat sau Fals? Dacă avem vectorul v = [10, 20, 30] și i=1, atunci i și v[i] au aceeași valoare.
Fals — i=1, dar v[1]=20. Indicele ≠ valoarea.
- Vectorul v = [5, 3, 8, 1]. Dacă i=2, cât este i? Dar v[i]? Sunt egale?
i=2, v[2]=8. Nu sunt egale.
Operații matematice de bază pe vectori
Suma elementelor
Suma se calculează adunând pe rând toate elementele. Inițializăm suma cu 0.
long long suma = 0; // folosim long long pentru sume mari
for (int i = 0; i < n; i++) {
suma += v[i]; // suma = suma + v[i];
}
Produsul elementelor
Produsul se calculează înmulțind toate elementele. Se inițializează cu 1, NU cu 0!
long long produs = 1; // ATENȚIE: se inițializează cu 1, nu cu 0!
for (int i = 0; i < n; i++) {
produs *= v[i]; // produs = produs * v[i];
}
Media aritmetică
Media aritmetică = suma elementelor împărțită la numărul de elemente.
// Mai întâi calculăm suma
long long suma = 0;
for (int i = 0; i < n; i++) {
suma += v[i];
}
// Apoi calculăm media (cu zecimale)
double media = (double)suma / n; // conversie la double pentru împărțire reală
// Afișăm cu 2 zecimale (necesită #include )
cout << fixed << setprecision(2) << media;
Suma pătratelor
Suma pătratelor = v[0] + v[1] + ... + v[n-1]
long long sumaPatrate = 0;
for (int i = 0; i < n; i++) {
sumaPatrate += (long long)v[i] * v[i]; // cast pentru a evita overflow
}
Suma cuburilor
Suma cuburilor = v[0] + v[1] + ... + v[n-1]
long long sumaCuburi = 0;
for (int i = 0; i < n; i++) {
sumaCuburi += (long long)v[i] * v[i] * v[i];
}
Calcule selective (cu condiții)
long long sumaPare = 0;
for (int i = 0; i < n; i++) {
if (v[i] % 2 == 0) {
sumaPare += v[i];
}
}
long long sumaPoz = 0;
int cntPoz = 0;
for (int i = 0; i < n; i++) {
if (v[i] > 0) {
sumaPoz += v[i];
cntPoz++;
}
}
double mediaPoz = (cntPoz > 0) ? (double)sumaPoz / cntPoz : 0;
Pregătire test - Ora 22
- Adevărat sau Fals? Când facem suma sau produsul a foarte multor valori, există riscul ca rezultatul să depășească capacitatea tipului
int.Adevărat — de aceea folosim long long. - Alegere multiplă: Vrem să calculăm produsul tuturor elementelor dintr-un vector. Cu ce valoare trebuie să inițializăm variabila
produs?
a)1
b)0
c) Primul element din vectora) 1 — dacă pornim cu 0, produsul rămâne mereu 0. - Alegere multiplă: Calculăm nota medie a elevilor și vrem rezultat cu zecimale. Ce tip de variabilă folosim pentru medie?
a)int
b)double
c)long longb) double — pentru rezultate cu zecimale. - Completează: Ca să acumulăm suma elementelor dintr-un vector, la fiecare pas scriem:
s = s + _______;v[i] - Completează: Ca să calculăm suma pătratelor elementelor, scriem:
s = s + _______;v[i] * v[i] - Completează: Când valorile calculate devin foarte mari și depășesc limita lui
int, trecem la tipul de date _______.long long
Definiția șirului lui Fibonacci
Șirul lui Fibonacci este definit prin următoarea recurență:
- F(0) = 0
- F(1) = 1
- F(n) = F(n-1) + F(n-2), pentru n ≥ 2
Primii termeni: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...
Generarea primilor n termeni (iterativ)
Folosim trei variabile pentru a memora ultimii doi termeni și termenul curent. Este eficient și nu necesită vector.
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
if (n <= 0) return 0;
if (n == 1) {
cout << 0;
return 0;
}
if (n == 2) {
cout << 0 << " " << 1;
return 0;
}
long long a = 0, b = 1, c;
cout << a << " " << b << " ";
for (int i = 2; i < n; i++) {
c = a + b;
cout << c << " ";
a = b;
b = c;
}
return 0;
}
Calculul celui de-al n-lea termen (F(n))
long long fibonacci(int n) {
if (n == 0) return 0;
if (n == 1) return 1;
long long a = 0, b = 1, c;
for (int i = 2; i <= n; i++) {
c = a + b;
a = b;
b = c;
}
return b;
}
Generare pentru n=6: 0 1 1 2 3 5
Proprietăți importante
- Fibonacci poate fi generat fără a folosi un vector, doar cu 3 variabile.
- Numerele Fibonacci cresc foarte repede. F(47) depășește 2 miliarde (limita int).
- Raportul dintre doi termeni consecutivi tinde spre numărul de aur φ ≈ 1.618.
long long. Pentru n > 90, depășește și long long.
Pregătire test - Ora 23
- Adevărat sau Fals? Singura modalitate de a calcula termenii Fibonacci este să-i stocăm pe toți într-un vector.
Fals — putem folosi doar 2-3 variabile simple, fără vector.
- Alegere multiplă: Primii doi termeni din șirul Fibonacci sunt:
a) 1 și 1
b) 0 și 2
c) 0 și 1c) 0 și 1 — F(0)=0, F(1)=1. - Completează: În șirul lui Fibonacci, fiecare termen nou se calculează prin _______ celor doi termeni anteriori.
adunarea
Ce este un șir recurent?
Șir recurent = un șir în care fiecare termen este definit pe baza unuia sau mai multor termeni anteriori, printr-o relație de recurență.
Factorialul (n!)
Definiție recurentă:
- 0! = 1
- n! = n * (n-1)!, pentru n ≥ 1
long long factorial(int n) {
long long fact = 1;
for (int i = 2; i <= n; i++) {
fact *= i;
}
return fact;
}
Primele valori: 0! = 1, 1! = 1, 2! = 2, 3! = 6, 4! = 24, 5! = 120, 6! = 720, ...
Șirul lui Lucas
Definiție:
- L(0) = 2
- L(1) = 1
- L(n) = L(n-1) + L(n-2), pentru n ≥ 2
Este similar cu Fibonacci, dar cu valori inițiale diferite.
long long lucas(int n) {
if (n == 0) return 2;
if (n == 1) return 1;
long long a = 2, b = 1, c;
for (int i = 2; i <= n; i++) {
c = a + b;
a = b;
b = c;
}
return b;
}
Primele valori Lucas: 2, 1, 3, 4, 7, 11, 18, 29, 47, 76, ...
Șirul Tribonacci
Definiție:
- T(0) = 0, T(1) = 0, T(2) = 1
- T(n) = T(n-1) + T(n-2) + T(n-3), pentru n ≥ 3
Generalizare a lui Fibonacci cu suma ultimilor trei termeni.
long long tribonacci(int n) {
if (n == 0 || n == 1) return 0;
if (n == 2) return 1;
long long a = 0, b = 0, c = 1, d;
for (int i = 3; i <= n; i++) {
d = a + b + c;
a = b;
b = c;
c = d;
}
return c;
}
Primele valori Tribonacci: 0, 0, 1, 1, 2, 4, 7, 13, 24, 44, ...
Comparație între Fibonacci și Lucas
| n | F(n) | L(n) |
|---|---|---|
| 0 | 0 | 2 |
| 1 | 1 | 1 |
| 2 | 1 | 3 |
| 3 | 2 | 4 |
| 4 | 3 | 7 |
| 5 | 5 | 11 |
| 6 | 8 | 18 |
| 7 | 13 | 29 |
| 8 | 21 | 47 |
| 9 | 34 | 76 |
Relație importantă: L(n) = F(n-1) + F(n+1). Exemplu: L(4) = F(3) + F(5) = 2 + 5 = 7.
Pregătire test - Ora 24
- Adevărat sau Fals? Factorialul numărului 0 are valoarea 1, atât în matematică cât și în programare.
Adevărat — 0! = 1 prin convenție matematică.
- Alegere multiplă: Într-un șir de tip Tribonacci, fiecare termen se obține adunând ultimele câte valori?
a) Două
b) Trei
c) Patrub) Trei — Tribonacci = suma ultimilor 3 termeni. - Completează: Șirul recurent care seamănă cu Fibonacci dar pornește de la valorile 2 și 1 poartă numele _______.
Lucas