Author: admin

  • Funcții Recursive: “Păpușile Matrioșka” ale Programării

    Bun venit la cea mai fascinantă și mai mind-bending lecție din programare! Dacă funcțiile normale sunt ca niște muncitori care-și fac treaba, funcțiile recursive sunt ca păpușile rusești (matrioșka) care se conțin pe ele însele!


    1. Ce este Recursivitatea? “Oglinda în Oglindă”

    Analogie cu viața reală:
    Imaginează-ți că stai între două oglinzi față în față. Ce vezi?

    • O oglindă arată o oglindă care arată o oglindă care arată…
    • Aceasta este recursivitate în natură!

    Definiție simplă:

    O funcție recursivă este o funcție care se apelează pe ea însăși.

    Cum gândește calculatorul:

    f(5) = 5 * f(4)
         = 5 * (4 * f(3))
         = 5 * (4 * (3 * f(2)))
         = 5 * (4 * (3 * (2 * f(1))))
         = 5 * (4 * (3 * (2 * 1)))
         = 120

    2. Structura unei Funcții Recursive: “Regulile Jocului”

    Orice funcție recursivă are DOUĂ părți esențiale:

    #include <iostream>
    using namespace std;
    
    void functieRecursiva(int n) {
        // 1. CONDIȚIA DE BAZĂ (cazul de oprire)
        // FĂRĂ ASTA - INFINITATE!
        if(n <= 0) {
            return;  // OPREȘTE recursivitatea!
        }
    
        // 2. APELUL RECURSIV (pasul recursiv)
        // cu un argument MAI MIC
        functieRecursiva(n - 1);
    }
    
    int main() {
        functieRecursiva(5);
        return 0;
    }

    Analogie cu scarile:

    void urca_scari(int trepte) {
        if(trepte == 0) {
            cout << "Am ajuns sus!";
            return;
        }
    
        cout << "Urc o treaptă... " << trepte << " rămase\n";
        urca_scari(trepte - 1);  // Urci și mai apoi urci și mai apoi...
    }

    3. Primul Exemplu: “Contorul Invers”

    #include <iostream>
    using namespace std;
    
    // Funcție care numără de la N la 1
    void numaraInvers(int n) {
        // CONDIȚIA DE BAZĂ
        if(n <= 0) {
            cout << "GATA!\n";
            return;
        }
    
        // AFIȘEAZĂ numărul curent
        cout << n << "... ";
    
        // APELEAZĂ-TE cu numărul MAI MIC
        numaraInvers(n - 1);
    }
    
    int main() {
        cout << "=== CONTOR INVERS RECURSIV ===\n\n";
    
        cout << "Număr de la 5 la 1:\n";
        numaraInvers(5);
    
        cout << "\nNumăr de la 3 la 1:\n";
        numaraInvers(3);
    
        return 0;
    }

    Output:

    === CONTOR INVERS RECURSIV ===
    
    Număr de la 5 la 1:
    5... 4... 3... 2... 1... GATA!
    
    Număr de la 3 la 1:
    3... 2... 1... GATA!

    Cum funcționează în memorie:

    numaraInvers(3)
    │
    ├── Afișează: 3...
    │   └── numaraInvers(2)
    │       │
    │       ├── Afișează: 2...
    │       │   └── numaraInvers(1)
    │       │       │
    │       │       ├── Afișează: 1...
    │       │       │   └── numaraInvers(0)
    │       │       │       │
    │       │       │       └── Afișează: GATA!
    │       │       └── ← se întoarce
    │       └── ← se întoarce
    └── ← se întoarce

    4. FACTORIAL – Exemplul Clasic

    Ce este factorial?

    5! = 5 × 4 × 3 × 2 × 1 = 120
    4! = 4 × 3 × 2 × 1 = 24
    1! = 1
    0! = 1  (by definition)

    Implementare recursivă:

    #include <iostream>
    using namespace std;
    
    // Funcție care calculează factorialul
    int factorial(int n) {
        // CONDIȚIA DE BAZĂ
        if(n <= 1) {
            return 1;  // 0! = 1 și 1! = 1
        }
    
        // APEL RECURSIV
        return n * factorial(n - 1);
    }
    
    int main() {
        cout << "=== FACTORIAL RECURSIV ===\n\n";
    
        cout << "Factorialul lui 5:\n";
        cout << "5! = " << factorial(5) << endl;
    
        cout << "\nCalcul pas cu pas:\n";
        cout << "factorial(5)\n";
        cout << "= 5 * factorial(4)\n";
        cout << "= 5 * (4 * factorial(3))\n";
        cout << "= 5 * (4 * (3 * factorial(2)))\n";
        cout << "= 5 * (4 * (3 * (2 * factorial(1))))\n";
        cout << "= 5 * (4 * (3 * (2 * 1)))\n";
        cout << "= 5 * (4 * (3 * 2))\n";
        cout << "= 5 * (4 * 6)\n";
        cout << "= 5 * 24\n";
        cout << "= 120\n";
    
        // Teste cu alte numere
        cout << "\nAlte teste:\n";
        cout << "0! = " << factorial(0) << endl;
        cout << "1! = " << factorial(1) << endl;
        cout << "6! = " << factorial(6) << endl;
    
        return 0;
    }

    5. FIBONACCI – “Familia de Iepuri”

    Șirul lui Fibonacci:

    0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...
    Regula: f(n) = f(n-1) + f(n-2)
    #include <iostream>
    using namespace std;
    
    int fibonacci(int n) {
        // CONDIȚIILE DE BAZĂ
        if(n == 0) return 0;
        if(n == 1) return 1;
    
        // APEL RECURSIV DUBLU
        return fibonacci(n - 1) + fibonacci(n - 2);
    }
    
    int main() {
        cout << "=== FIBONACCI RECURSIV ===\n\n";
    
        cout << "Primii 10 termeni Fibonacci:\n";
        for(int i = 0; i < 10; i++) {
            cout << "f(" << i << ") = " << fibonacci(i) << endl;
        }
    
        cout << "\nCum se calculează f(4):\n";
        cout << "f(4) = f(3) + f(2)\n";
        cout << "     = (f(2) + f(1)) + (f(1) + f(0))\n";
        cout << "     = ((f(1) + f(0)) + 1) + (1 + 0)\n";
        cout << "     = ((1 + 0) + 1) + 1\n";
        cout << "     = (1 + 1) + 1\n";
        cout << "     = 2 + 1\n";
        cout << "     = 3\n";
    
        return 0;
    }

    Problema cu Fibonacci recursiv:

    // ATENȚIE! Această implementare este INEFICIENTĂ!
    // Calculează aceleași valori de multe ori!
    
    // Pentru n = 5:
    // f(5) = f(4) + f(3)
    // f(4) = f(3) + f(2)   ← f(3) calculat DIN NOU!
    // f(3) = f(2) + f(1)   ← f(2) calculat DIN NOU!
    // ... și tot așa...

    6. Suma Cifrelor unui Număr

    #include <iostream>
    using namespace std;
    
    int sumaCifre(int n) {
        // CONDIȚIA DE BAZĂ
        if(n == 0) {
            return 0;
        }
    
        // APEL RECURSIV
        // Ultima cifră + suma cifrelor rămase
        return (n % 10) + sumaCifre(n / 10);
    }
    
    int main() {
        cout << "=== SUMA CIFRELOR RECURSIV ===\n\n";
    
        int numar = 12345;
        cout << "Suma cifrelor lui " << numar << ":\n";
        cout << sumaCifre(numar) << endl;
    
        cout << "\nCum funcționează:\n";
        cout << "sumaCifre(12345)\n";
        cout << "= 5 + sumaCifre(1234)\n";
        cout << "= 5 + (4 + sumaCifre(123))\n";
        cout << "= 5 + (4 + (3 + sumaCifre(12)))\n";
        cout << "= 5 + (4 + (3 + (2 + sumaCifre(1))))\n";
        cout << "= 5 + (4 + (3 + (2 + (1 + sumaCifre(0)))))\n";
        cout << "= 5 + (4 + (3 + (2 + (1 + 0))))\n";
        cout << "= 5 + (4 + (3 + (2 + 1)))\n";
        cout << "= 5 + (4 + (3 + 3))\n";
        cout << "= 5 + (4 + 6)\n";
        cout << "= 5 + 10\n";
        cout << "= 15\n";
    
        return 0;
    }

    7. CMMDC (Cel Mai Mare Divizor Comun)

    Algoritmul lui Euclid:

    cmmdc(a, b) = cmmdc(b, a % b)
    cmmdc(a, 0) = a
    #include <iostream>
    using namespace std;
    
    int cmmdc(int a, int b) {
        // CONDIȚIA DE BAZĂ
        if(b == 0) {
            return a;
        }
    
        // APEL RECURSIV
        return cmmdc(b, a % b);
    }
    
    int main() {
        cout << "=== CMMDC RECURSIV (Euclid) ===\n\n";
    
        cout << "cmmdc(48, 18) = " << cmmdc(48, 18) << endl;
        cout << "cmmdc(56, 98) = " << cmmdc(56, 98) << endl;
        cout << "cmmdc(17, 13) = " << cmmdc(17, 13) << endl;
    
        cout << "\nExplicație pentru cmmdc(48, 18):\n";
        cout << "cmmdc(48, 18)\n";
        cout << "= cmmdc(18, 48 % 18) = cmmdc(18, 12)\n";
        cout << "= cmmdc(12, 18 % 12) = cmmdc(12, 6)\n";
        cout << "= cmmdc(6, 12 % 6) = cmmdc(6, 0)\n";
        cout << "= 6\n";
    
        return 0;
    }

    8. Parcurgerea unui Vector

    #include <iostream>
    using namespace std;
    
    // Afișează elementele unui vector recursiv
    void afiseazaVector(int v[], int n) {
        // CONDIȚIA DE BAZĂ
        if(n == 0) {
            return;
        }
    
        // Afișează PRIMUL element
        cout << v[0] << " ";
    
        // Apel recursiv cu RESTUL vectorului
        afiseazaVector(v + 1, n - 1);
    }
    
    // Calculează suma elementelor
    int sumaVector(int v[], int n) {
        if(n == 0) {
            return 0;
        }
    
        return v[0] + sumaVector(v + 1, n - 1);
    }
    
    // Găsește maximul
    int maximVector(int v[], int n) {
        if(n == 1) {
            return v[0];
        }
    
        int maxRest = maximVector(v + 1, n - 1);
    
        if(v[0] > maxRest) {
            return v[0];
        } else {
            return maxRest;
        }
    }
    
    int main() {
        cout << "=== OPERAȚII CU VECTORI RECURSIV ===\n\n";
    
        int vector[] = {5, 2, 8, 1, 9, 3};
        int lungime = 6;
    
        cout << "Vectorul: ";
        afiseazaVector(vector, lungime);
        cout << endl;
    
        cout << "Suma: " << sumaVector(vector, lungime) << endl;
        cout << "Maxim: " << maximVector(vector, lungime) << endl;
    
        return 0;
    }

    9. Turnurile din Hanoi

    Problema clasică de recursivitate:

    Avem 3 tije: A, B, C
    Și n discuri de dimensiuni diferite pe tija A
    Reguli:
    1. Mută un singur disc odată
    2. Nu pune disc mare peste disc mic
    3. Mută toate discurile pe tija C
    #include <iostream>
    using namespace std;
    
    void hanoi(int n, char sursa, char destinatie, char auxiliar) {
        // CONDIȚIA DE BAZĂ
        if(n == 1) {
            cout << "Mută disc 1 de pe " << sursa << " pe " << destinatie << endl;
            return;
        }
    
        // APELURI RECURSIVE
        // 1. Mută n-1 discuri de pe sursa pe auxiliar
        hanoi(n - 1, sursa, auxiliar, destinatie);
    
        // 2. Mută discul n de pe sursa pe destinatie
        cout << "Mută disc " << n << " de pe " << sursa << " pe " << destinatie << endl;
    
        // 3. Mută n-1 discuri de pe auxiliar pe destinatie
        hanoi(n - 1, auxiliar, destinatie, sursa);
    }
    
    int main() {
        cout << "=== TURNURILE DIN HANOI ===\n\n";
    
        cout << "Soluția pentru 3 discuri:\n";
        hanoi(3, 'A', 'C', 'B');
    
        cout << "\nNumărul minim de mutări pentru n discuri: 2^n - 1\n";
        cout << "3 discuri: 2^3 - 1 = 7 mutări\n";
        cout << "5 discuri: 2^5 - 1 = 31 mutări\n";
        cout << "64 discuri: 2^64 - 1 ≈ 18.4 trilioane mutări!\n";
    
        return 0;
    }

    10. Căutarea Binară Recursivă

    #include <iostream>
    using namespace std;
    
    int cautareBinara(int v[], int stanga, int dreapta, int x) {
        // CONDIȚIA DE BAZĂ
        if(stanga > dreapta) {
            return -1;  // Nu s-a găsit
        }
    
        // Calculează mijlocul
        int mijloc = stanga + (dreapta - stanga) / 2;
    
        // Dacă l-am găsit
        if(v[mijloc] == x) {
            return mijloc;
        }
    
        // Dacă x e mai mic, căutăm în stânga
        if(x < v[mijloc]) {
            return cautareBinara(v, stanga, mijloc - 1, x);
        }
    
        // Dacă x e mai mare, căutăm în dreapta
        return cautareBinara(v, mijloc + 1, dreapta, x);
    }
    
    int main() {
        cout << "=== CĂUTARE BINARĂ RECURSIVĂ ===\n\n";
    
        int vector[] = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19};
        int lungime = 10;
    
        int caut = 13;
        int pozitie = cautareBinara(vector, 0, lungime - 1, caut);
    
        if(pozitie != -1) {
            cout << "Am găsit " << caut << " la poziția " << pozitie << endl;
        } else {
            cout << caut << " nu a fost găsit\n";
        }
    
        return 0;
    }

    11. Recursivitate vs Iterativitate

    #include <iostream>
    using namespace std;
    
    // VERSIUNE RECURSIVĂ
    int factorialRecursiv(int n) {
        if(n <= 1) return 1;
        return n * factorialRecursiv(n - 1);
    }
    
    // VERSIUNE ITERATIVĂ
    int factorialIterativ(int n) {
        int result = 1;
        for(int i = 2; i <= n; i++) {
            result *= i;
        }
        return result;
    }
    
    int main() {
        cout << "=== RECURSIV vs ITERATIV ===\n\n";
    
        cout << "Factorial recursiv vs iterativ:\n";
        cout << "5! recursiv = " << factorialRecursiv(5) << endl;
        cout << "5! iterativ = " << factorialIterativ(5) << endl;
    
        cout << "\n--- AVANTAJE ---\n";
        cout << "RECURSIVITATE:\n";
        cout << "+ Cod mai elegant și concis\n";
        cout << "+ Natural pentru probleme recursive (arbori, divide-et-impera)\n";
        cout << "+ Mai ușor de înțeles pentru anumite probleme\n\n";
    
        cout << "ITERATIVITATE:\n";
        cout << "+ Mai rapid (fără overhead de apeluri)\n";
        cout << "+ Folosește mai puțină memorie (fără stack)\n";
        cout << "+ Nu riscă stack overflow\n";
    
        cout << "\n--- DEZAVANTAJE ---\n";
        cout << "RECURSIVITATE:\n";
        cout << "- Poate cauza stack overflow pentru adâncimi mari\n";
        cout << "- Mai lent din cauza apelurilor de funcții\n";
        cout << "- Consumă mai multă memorie\n\n";
    
        cout << "ITERATIVITATE:\n";
        cout << "- Cod mai lung și mai complex pentru unele probleme\n";
        cout << "- Mai greu de înțeles pentru algoritmi natural recursivi\n";
    
        return 0;
    }

    12. Recursivitate Indirectă: “Dansul Funcțiilor”

    #include <iostream>
    using namespace std;
    
    // Declarații înainte (forward declarations)
    void functieA(int n);
    void functieB(int n);
    
    void functieA(int n) {
        if(n <= 0) {
            return;
        }
    
        cout << "A: " << n << endl;
        functieB(n - 1);
    }
    
    void functieB(int n) {
        if(n <= 0) {
            return;
        }
    
        cout << "B: " << n << endl;
        functieA(n - 1);
    }
    
    int main() {
        cout << "=== RECURSIVITATE INDIRECTĂ ===\n\n";
    
        cout << "A și B se apelează reciproc:\n";
        functieA(5);
    
        return 0;
    }

    13. Reguli de Aur pentru Recursivitate

    REGULA 1: Mereu ai nevoie de un CAZ DE BAZĂ

    // GREȘIT - RECURSIVITATE INFINITĂ!
    int factorialGresit(int n) {
        return n * factorialGresit(n - 1);  // NICIODATĂ nu se oprește!
    }
    
    // CORECT
    int factorialCorect(int n) {
        if(n <= 1) {  // CAZ DE BAZĂ
            return 1;
        }
        return n * factorialCorect(n - 1);
    }

    REGULA 2: Argumentul trebuie să se apropie de cazul de bază

    // GREȘIT
    int recursivitateProasta(int n) {
        if(n <= 0) return 0;
        return recursivitateProasta(n);  // La fel ca înainte - INFINIT!
    }
    
    // CORECT
    int recursivitateBuna(int n) {
        if(n <= 0) return 0;
        return recursivitateBuna(n - 1);  // Se apropie de 0!
    }

    REGULA 3: Stack Overflow este REAL

    int factorialMare(int n) {
        if(n <= 1) return 1;
        return n * factorialMare(n - 1);
    }
    
    // factorialMare(10000) va da STACK OVERFLOW!
    // Soluție: folosește iterativ pentru numere mari

    REGULA 4: Divide et Impera

    // Problemele bune pentru recursivitate:
    // 1. Se pot împărți în subprobleme mai mici
    // 2. Subproblemele sunt similare cu problema inițială
    // 3. Există un caz de bază simplu

    14. Exerciții Practice

    #include <iostream>
    using namespace std;
    
    // EXERCIȚIU 1: Inversarea unui șir
    void inversareSir(char s[], int start, int end) {
        if(start >= end) {
            return;
        }
    
        // Schimbă caracterele
        char temp = s[start];
        s[start] = s[end];
        s[end] = temp;
    
        // Apel recursiv pentru restul
        inversareSir(s, start + 1, end - 1);
    }
    
    // EXERCIȚIU 2: Puterea unui număr
    int putere(int baza, int exponent) {
        if(exponent == 0) {
            return 1;
        }
    
        return baza * putere(baza, exponent - 1);
    }
    
    // EXERCIȚIU 3: Verifică palindrom
    bool estePalindrom(char s[], int start, int end) {
        if(start >= end) {
            return true;
        }
    
        if(s[start] != s[end]) {
            return false;
        }
    
        return estePalindrom(s, start + 1, end - 1);
    }
    
    int main() {
        cout << "=== EXERCIȚII PRACTICE ===\n\n";
    
        // Test inversare șir
        char sir[] = "recursivitate";
        cout << "Șir original: " << sir << endl;
        inversareSir(sir, 0, 12);
        cout << "Șir inversat: " << sir << endl;
    
        // Test putere
        cout << "\n2^5 = " << putere(2, 5) << endl;
        cout << "3^4 = " << putere(3, 4) << endl;
    
        // Test palindrom
        char palindrom[] = "capac";
        char nonpalindrom[] = "calculator";
    
        cout << "\nVerificare palindrom:\n";
        cout << "'capac' este palindrom? " 
             << (estePalindrom(palindrom, 0, 4) ? "DA" : "NU") << endl;
        cout << "'calculator' este palindrom? " 
             << (estePalindrom(nonpalindrom, 0, 9) ? "DA" : "NU") << endl;
    
        return 0;
    }

    15. Concluzie: Când să Folosești Recursivitatea?

    FOLOSEȘTE recursivitate când:

    1. Problema este natural recursivă (arbori, grafuri)
    2. Codul iterativ ar fi foarte complex
    3. Performanța nu este critică
    4. Adâncimea recursivă este mică

    EVITĂ recursivitatea când:

    1. Adâncimea poate fi foarte mare (risc stack overflow)
    2. Performanța este critică
    3. Codul iterativ este la fel de simplu

    Probleme clasice pentru recursivitate:

    ✅ Factorial, Fibonacci
    ✅ Turnurile din Hanoi
    ✅ Parcurgerea arborilor
    ✅ Divide et impera (QuickSort, MergeSort)
    ✅ Backtracking

    // Ultimul sfat:
    // Recursivitatea este ca un superputere.
    // Folosește-o cu înțelepciune!
    
    // Când e bine folosită, creează cod elegant și puternic.
    // Când e prost folosită, creează probleme grave.
    
    // Exersază, înțelege, și folosește cu discernământ!
    // Happy recursive coding! 🔄🎯

    Remember: Recursivitatea nu este doar o tehnică de programare – este un mod de gândire! Învață să vezi problemele ca fiind compuse din versiuni mai mici ale lor însele, și vei deveni un programator mult mai bun!

  • Fișiere Text în C++: “Memoria Permanentă” a Calculatorului

    Bun venit la cea mai importantă lecție din viața unui program! Dacă până acum am lucrat cu date “pe viu” în memorie, acum învățăm cum să le salvăm și să le recuperăm, exact cum faci cu pozele pe telefon sau documentele pe calculator!

    1. Ce sunt Fișierele Text? “Caietul de Notițe” al Programului

    Analogie cu viața reală:

    • Memoria RAM = tabla cu cretă (se șterge când dai drumul la curent)
    • Fișierul text = caiet în care scrii (rămâne și după ce închizi calculatorul)

    Cum gândește calculatorul:

    Calculatorul vede: 
    F I Ș I E R . T X T
    ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
    01000110 01001001 ...

    Dar NOI îl vedem ca pe text normal!


    2. Tipuri de Acces: “Cum Citești o Carte”

    A. Acces Secvențial – “Cititul Pagină cu Pagină”

    Imaginează-ți o casetă audio:

    • Pornesti de la început
    • Asculți piesa 1, apoi 2, apoi 3…
    • NU poți sări direct la piesa 3 fără să treci prin 1 și 2
    #include <iostream>
    #include <fstream>  // BIBLIOTECA MAGICĂ pentru fișiere!
    using namespace std;
    
    int main() {
        cout << "=== ACCES SECVENȚIAL ===\n";
        cout << "(ca o casetă audio)\n\n";
    
        // Scriere secvențială
        ofstream caseta_out("casetta.txt");
    
        caseta_out << "Piesa 1: Hello World\n";
        caseta_out << "Piesa 2: Salut Romania\n";
        caseta_out << "Piesa 3: La revedere\n";
    
        caseta_out.close();  // ÎNCHIDE întotdeauna caseta!
    
        // Citire secvențială
        ifstream caseta_in("casetta.txt");
        string linie;
    
        cout << "Ascult caseta de la început:\n";
        while(getline(caseta_in, linie)) {
            cout << "▶ " << linie << endl;
        }
    
        caseta_in.close();
    
        return 0;
    }

    B. Acces Aleator (Random Access) – “DVD-ul cu Butoane”

    Imaginează-ți un DVD:

    • Poți sări la scena 5 direct
    • Poți derula înainte/înapoi
    • Ai butoane de control
    #include <iostream>
    #include <fstream>
    using namespace std;
    
    int main() {
        cout << "=== ACCES ALEATOR ===\n";
        cout << "(ca un DVD cu telecomanda)\n\n";
    
        // Creăm un "DVD" cu scene
        fstream dvd("filmul_meu.txt", ios::out);
    
        dvd << "Scena 1: Începutul\n";
        dvd << "Scena 2: Acțiunea\n";
        dvd << "Scena 3: Climaxul\n";
        dvd << "Scena 4: Sfârșitul\n";
    
        dvd.close();
    
        // Acum citim ca la DVD!
        fstream dvd_in("filmul_meu.txt", ios::in);
    
        // Sărim direct la scena 3
        // Găsim unde începe fiecare scenă...
        dvd_in.seekg(0, ios::end);  // Mergem la sfârșit
        int lungime = dvd_in.tellg();  // Aflăm lungimea totală
    
        cout << "Lungimea filmului: " << lungime << " caractere\n\n";
    
        // Mergem înapoi la începutul scenei 3
        dvd_in.seekg(30, ios::beg);  // Sărim la caracterul 30
    
        string scena3;
        getline(dvd_in, scena3);
        cout << "Am sărit la: " << scena3 << endl;
    
        dvd_in.close();
    
        return 0;
    }

    3. Biblioteca <fstream> – “Cutia cu Instrumente”

    Cele 3 instrumente principale:

    #include <iostream>
    #include <fstream>
    using namespace std;
    
    int main() {
        cout << "=== INSTRUMENTELE DIN <fstream> ===\n\n";
    
        // 1. OFSTREAM - "Scriitorul"
        // Doar SCRIE în fișier
        cout << "1. ofstream - SCRIITORUL:\n";
        ofstream scriitor("jurnal.txt");
    
        if(scriitor.is_open()) {  // VERIFICĂ dacă s-a deschis
            scriitor << "Azi am învățat C++\n";
            scriitor << "Este foarte interesant!\n";
            scriitor.close();
            cout << "   ✓ Am scris în jurnal\n";
        } else {
            cout << "   ✗ Nu pot deschide jurnalul\n";
        }
    
        // 2. IFSTREAM - "Cititorul"
        // Doar CITEȘTE din fișier
        cout << "\n2. ifstream - CITITORUL:\n";
        ifstream cititor("jurnal.txt");
    
        if(cititor.is_open()) {
            string linie;
            cout << "   Conținutul jurnalului:\n";
    
            while(getline(cititor, linie)) {
                cout << "   • " << linie << endl;
            }
    
            cititor.close();
        }
    
        // 3. FSTREAM - "Actorul Universal"
        // Poate atât CITI cât și SCRIE
        cout << "\n3. fstream - ACTORUL UNIVERSAL:\n";
        fstream universal("notite.txt", ios::out | ios::in | ios::app);
    
        if(universal.is_open()) {
            // Scrie ceva
            universal << "Notita 1: Cumpar lapte\n";
    
            // Citește ce am scris
            universal.seekg(0);  // Înapoi la început
    
            string continut;
            getline(universal, continut);
            cout << "   Am citit: " << continut << endl;
    
            universal.close();
        }
    
        return 0;
    }

    4. Moduri de Deschidere – “Cheile” pentru Fișiere

    #include <iostream>
    #include <fstream>
    using namespace std;
    
    int main() {
        cout << "=== MODURILE DE DESCHIDERE ===\n";
        cout << "(diferite 'chei' pentru diferite uși)\n\n";
    
        // ios::out - "Scrie peste tot"
        // Dacă fișierul există, îl șterge și începe de la 0
        ofstream out("test_out.txt", ios::out);
        out << "Scriere cu ios::out\n";
        out.close();
    
        // ios::app - "Adaugă la sfârșit"
        // Ca să adaugi la un jurnal existent
        ofstream app("test_app.txt", ios::app);
        app << "Linie 1\n";
        app << "Linie 2\n";  // Se adaugă după Linie 1
        app.close();
    
        // ios::in - "Doar citire"
        // Doar citești, nu poți modifica
        ifstream in("test_app.txt", ios::in);
        // ... citește
        in.close();
    
        // ios::ate - "Sari la Sfârșit"
        // Deschide și sări direct la final
        fstream ate("test_app.txt", ios::ate | ios::in);
        ate << "Linie adăugată la sfârșit\n";
        ate.close();
    
        // ios::binary - "Mod binar"
        // Pentru imagini, sunete, executabile
        // (nu pentru text normal)
    
        cout << "Moduri comune combinate:\n";
        cout << "• ios::out | ios::app  - adaugă la sfârșit\n";
        cout << "• ios::in | ios::out   - citește și scrie\n";
        cout << "• ios::binary | ios::in - citire binară\n";
    
        return 0;
    }

    5. Cum Gândește Calculatorul cu Fișierele?

    Imaginează-ți un cărăuș cu cărți:

    #include <iostream>
    #include <fstream>
    using namespace std;
    
    int main() {
        cout << "=== CĂRĂUȘUL DE DATE ===\n\n";
    
        // 1. DESCHIDEREA - "Deschid ușa depozitului"
        fstream depozit("depozit.txt", ios::out);
    
        if(!depozit) {  // Verificare rapidă
            cout << "Ups! Nu pot deschide depozitul!\n";
            return 1;
        }
    
        // 2. SCRIEREA - "Pun cutii în depozit"
        cout << "Pun în depozit:\n";
        cout << " - Cutia 'Mere': 10kg\n";
        cout << " - Cutia 'Pere': 5kg\n";
        cout << " - Cutia 'Banane': 3kg\n\n";
    
        depozit << "Mere 10\n";
        depozit << "Pere 5\n";
        depozit << "Banane 3\n";
    
        // 3. ÎNCHIDEREA - "Închid ușa și încui"
        depozit.close();
        cout << "✓ Depozitul este închis și securizat!\n\n";
    
        // 4. REDESCHIDEREA - "Vin a doua zi la depozit"
        cout << "A doua zi...\n";
        depozit.open("depozit.txt", ios::in);
    
        // 5. CITIREA - "Verific ce am în depozit"
        cout << "Verific inventarul:\n";
    
        string produs;
        int cantitate;
    
        while(depozit >> produs >> cantitate) {
            cout << " • " << produs << ": " << cantitate << "kg\n";
        }
    
        depozit.close();
    
        // 6. ADAUGARE - "Mai aduc marfă"
        cout << "\nMai aduc mere...\n";
    
        ofstream adauga("depozit.txt", ios::app);  // APPEND!
        adauga << "Mere 5\n";  // +5kg mere
        adauga.close();
    
        cout << "✓ Am adăugat 5kg mere\n";
    
        return 0;
    }

    6. Lucrul cu Linii Complete

    #include <iostream>
    #include <fstream>
    #include <string>
    using namespace std;
    
    int main() {
        cout << "=== JURNALUL ELEVULUI ===\n\n";
    
        // Scriere cu getline
        ofstream jurnal("jurnal.txt");
    
        cout << "Scrie în jurnal (scrie 'stop' pe linie nouă pentru a încheia):\n";
    
        string intrare;
        while(true) {
            cout << "> ";
            getline(cin, intrare);
    
            if(intrare == "stop") {
                break;
            }
    
            jurnal << intrare << endl;
        }
    
        jurnal.close();
    
        // Citire cu getline
        cout << "\n--- CITIRE JURNAL ---\n";
    
        ifstream citire_jurnal("jurnal.txt");
        string linie;
        int numar_linie = 1;
    
        while(getline(citire_jurnal, linie)) {
            cout << numar_linie << ". " << linie << endl;
            numar_linie++;
        }
    
        citire_jurnal.close();
    
        return 0;
    }

    7. Verificări și Erori – “Sistemul de Alarmă”

    #include <iostream>
    #include <fstream>
    using namespace std;
    
    int main() {
        cout << "=== SISTEMUL DE VERIFICARE ===\n\n";
    
        // Încerc să deschid un fișier care NU există
        ifstream fantoma("fisier_care_nu_exista.txt");
    
        cout << "1. Verific existența:\n";
        if(!fantoma) {
            cout << "   ✗ Fișierul nu există!\n";
            cout << "   (Calculatorul zice: 'Nu-l găsesc, boss!')\n";
        }
    
        cout << "\n2. Verific dacă e deschis:\n";
        if(!fantoma.is_open()) {
            cout << "   ✗ Nu e deschis (normal, nu există!)\n";
        }
    
        cout << "\n3. Verific sfârșitul fișierului (eof):\n";
        ifstream existent("existent.txt");
    
        if(existent) {
            string temp;
            while(!existent.eof()) {  // Cat timp NU am ajuns la End Of File
                getline(existent, temp);
                cout << "   Am citit: " << temp << endl;
            }
            cout << "   ✓ Am ajuns la sfârșitul fișierului\n";
        }
    
        cout << "\n4. Verificări rapide:\n";
        cout << "   • if(fisier)           - fișierul e bun\n";
        cout << "   • fisier.good()        - totul e în regulă\n";
        cout << "   • fisier.fail()        - ceva n-a mers bine\n";
        cout << "   • fisier.bad()         - eroare gravă\n";
        cout << "   • fisier.eof()         - am ajuns la sfârșit\n";
    
        return 0;
    }

    8. Exemplu Complex: “Agenda Telefonică”

    #include <iostream>
    #include <fstream>
    #include <string>
    using namespace std;
    
    struct Contact {
        string nume;
        string telefon;
        string email;
    };
    
    int main() {
        cout << "=== AGENDA TELEFONICĂ DIGITALĂ ===\n\n";
    
        // Meniu principal
        int optiune;
    
        do {
            cout << "\n=== MENIU ===\n";
            cout << "1. Adaugă contact\n";
            cout << "2. Vezi toate contactele\n";
            cout << "3. Caută contact\n";
            cout << "4. Ieșire\n";
            cout << "Alege: ";
            cin >> optiune;
            cin.ignore();  // Important!
    
            switch(optiune) {
                case 1: {
                    // ADAUGARE CONTACT
                    Contact nou;
    
                    cout << "\n--- ADAUGĂ CONTACT ---\n";
                    cout << "Nume: ";
                    getline(cin, nou.nume);
    
                    cout << "Telefon: ";
                    getline(cin, nou.telefon);
    
                    cout << "Email: ";
                    getline(cin, nou.email);
    
                    // Scrie în fișier (adaugă la sfârșit)
                    ofstream agenda("agenda.txt", ios::app);
    
                    if(agenda.is_open()) {
                        agenda << nou.nume << "," 
                               << nou.telefon << "," 
                               << nou.email << endl;
    
                        agenda.close();
                        cout << "✓ Contact salvat!\n";
                    } else {
                        cout << "✗ Eroare la salvare!\n";
                    }
                    break;
                }
    
                case 2: {
                    // AFIȘARE TOATE CONTACTELE
                    cout << "\n--- LISTA CONTACTE ---\n";
    
                    ifstream agenda("agenda.txt");
    
                    if(agenda.is_open()) {
                        string linie;
                        int nr = 1;
    
                        while(getline(agenda, linie)) {
                            // Găsește virgulele
                            size_t virgula1 = linie.find(',');
                            size_t virgula2 = linie.find(',', virgula1 + 1);
    
                            if(virgula1 != string::npos && virgula2 != string::npos) {
                                string nume = linie.substr(0, virgula1);
                                string telefon = linie.substr(virgula1 + 1, virgula2 - virgula1 - 1);
                                string email = linie.substr(virgula2 + 1);
    
                                cout << nr << ". " << nume << endl;
                                cout << "   Tel: " << telefon << endl;
                                cout << "   Email: " << email << endl;
                                cout << endl;
    
                                nr++;
                            }
                        }
    
                        agenda.close();
    
                        if(nr == 1) {
                            cout << "Agenda este goală!\n";
                        }
                    } else {
                        cout << "Nu am găsit agenda!\n";
                    }
                    break;
                }
    
                case 3: {
                    // CĂUTARE CONTACT
                    cout << "\n--- CĂUTARE CONTACT ---\n";
                    cout << "Nume de căutat: ";
    
                    string cauta;
                    getline(cin, cauta);
    
                    ifstream agenda("agenda.txt");
                    bool gasit = false;
    
                    if(agenda.is_open()) {
                        string linie;
    
                        while(getline(agenda, linie)) {
                            // Extrage numele (prima parte până la virgulă)
                            size_t virgula = linie.find(',');
                            string nume = linie.substr(0, virgula);
    
                            // Verifică dacă se potrivește
                            if(nume.find(cauta) != string::npos) {
                                cout << "\n✓ CONTACT GĂSIT:\n";
                                cout << "Nume: " << nume << endl;
    
                                // Extrage telefonul
                                size_t virgula2 = linie.find(',', virgula + 1);
                                string telefon = linie.substr(virgula + 1, virgula2 - virgula - 1);
                                cout << "Tel: " << telefon << endl;
    
                                // Extrage email
                                string email = linie.substr(virgula2 + 1);
                                cout << "Email: " << email << endl;
    
                                gasit = true;
                            }
                        }
    
                        agenda.close();
    
                        if(!gasit) {
                            cout << "✗ Nu am găsit contactul '" << cauta << "'\n";
                        }
                    }
                    break;
                }
    
                case 4:
                    cout << "\nLa revedere! Agenda a fost salvată.\n";
                    break;
    
                default:
                    cout << "\n✗ Opțiune invalidă!\n";
            }
    
        } while(optiune != 4);
    
        return 0;
    }

    9. Reguli de Aur pentru Fișiere Text

    REGULA 1: Închide întotdeauna fișierul!

    // GREȘIT
    ofstream fisier("test.txt");
    fisier << "ceva";
    // ... programul se încheie fără close()
    
    // CORECT
    ofstream fisier("test.txt");
    fisier << "ceva";
    fisier.close();  // ÎNCHIDE!

    REGULA 2: Verifică dacă s-a deschis!

    ofstream fisier("test.txt");
    
    if(fisier.is_open()) {  // SAU: if(fisier)
        // ... operatii
    } else {
        cout << "Eroare la deschidere!";
    }

    REGULA 3: Folosește ios::app pentru adăugare

    // Dacă vrei să adaugi, NU să înlocuiești:
    ofstream fisier("jurnal.txt", ios::app);  // APPEND!

    REGULA 4: Șterge enter-ul cu cin.ignore()

    int varsta;
    string nume;
    
    cout << "Varsta: ";
    cin >> varsta;
    
    cin.ignore();  // ȘTERGE ENTER-UL RĂMAS!
    
    cout << "Nume: ";
    getline(cin, nume);  // Acum merge bine!

    10. Exercițiu Final: “Jocul Memoriei”

    #include <iostream>
    #include <fstream>
    #include <string>
    #include <ctime>
    using namespace std;
    
    int main() {
        cout << "=== JOCUL MEMORIEI ===\n";
        cout << "Scrie ce vrei, iar calculatorul își va aminti!\n\n";
    
        // Deschide sau creează fișierul
        fstream memoria("memorie.txt", ios::in | ios::out | ios::app);
    
        if(!memoria.is_open()) {
            // Dacă nu există, îl creează
            memoria.open("memorie.txt", ios::out);
            memoria << "=== JOCUL MEMORIEI ===\n";
            memoria.close();
    
            memoria.open("memorie.txt", ios::in | ios::out | ios::app);
        }
    
        // Citește ce era deja
        cout << "AMINTIRILE ANTERIOARE:\n";
        cout << "----------------------\n";
    
        memoria.seekg(0);  // Mergi la început
        string linie;
    
        while(getline(memoria, linie)) {
            cout << linie << endl;
        }
    
        // Adaugă amintire nouă
        cout << "\n--- ADAUGĂ O AMINTIRE ---\n";
        cout << "Scrie ceva (scrie 'gata' pentru a încheia):\n";
    
        string amintire;
        time_t acum = time(0);
        char* data = ctime(&acum);
    
        memoria << "\n[" << data << "]\n";
    
        while(true) {
            cout << "> ";
            getline(cin, amintire);
    
            if(amintire == "gata") {
                break;
            }
    
            memoria << "- " << amintire << endl;
        }
    
        memoria << "----------------------\n";
    
        memoria.close();
    
        cout << "\n✓ Am salvat amintirea!\n";
        cout << "Data viitoare când vei rula programul,\n";
        cout << "vei vedea și amintirile vechi!\n";
    
        return 0;
    }

    CONCLUZIE: De ce sunt importante fișierele?

    1. Persistență – Datele rămân și după ce închizi programul
    2. Partajare – Poți trimite fișierul altcuiva
    3. Backup – Poți salva progresul în jocuri/programe
    4. Logging – Programele “țin jurnal” cu ce fac

    Gândiți-vă la fișiere ca la:

    • Jurnal personal pentru program
    • Cutie de valori pentru date importante
    • Memorie externă pentru calculator

    Ultimul sfat:

    // Întotdeauna tratează fișierele cu grijă!
    // E ca și cum ai avea grijă de un caiet prețios.
    
    // Verifică, închide, și fii atent la erori!
    // Happy coding! 📁✨
  • Funcții Predefinite pentru String-uri: “Magia” din în C++ și Pascal

    Bun venit la cel mai fun atelier de string-uri! Dacă șirurile de caractere sunt cuvintele calculatorului, atunci funcțiile predefinite sunt trucurile de magie pe care le poți face cu ele. Hai să vedem ce instrumente fantastice ne oferă C++ (doar cu <iostream> și <string>) și Pascal!

    1. Ce este un Șir de Caractere? “Un Tren de Caractere”

    Gândește-te la un șir de caractere ca la un tren unde fiecare vagon este o literă, cifră sau simbol:

    • Șir: “Salut”
    • Caractere: ‘S’ ‘a’ ‘l’ ‘u’ ‘t’
    • Terminator: ‘\0’ (caracterul invizibil de la sfârșit)

    Analogie cu un Cuvânt Într-o Cutie:

    Cutia poate conține: S a l u t \0 \0 \0 \0 \0
    Unde \0 e terminatorul care spune “aici se termină cuvântul”


    Partea 1: C++ cu <string> – Magicianul Modern

    A. Setul de Bază: “Cele 7 Minuni” ale String-ului

    #include <iostream>
    #include <string>  // ASTA E SINGURA BIBLIOTECĂ DE CARE AVEM NEVOIE!
    using namespace std;
    
    int main() {
        cout << "=== MAGIA STRING-URILOR în C++ ===\n\n";
    
        // 1. CREAREA - "Născocirea din nimic"
        string magie1 = "Abracadabra!";
        string magie2("Hocus Pocus");
        string magie3 = magie1;  // O clonă perfectă!
    
        cout << "1. CREARE:\n";
        cout << "   magie1: " << magie1 << endl;
        cout << "   magie2: " << magie2 << endl;
        cout << "   magie3 (clona): " << magie3 << endl;
    
        // 2. LUNGIMEA - "Ruleta Magică"
        cout << "\n2. LUNGIME:\n";
        cout << "   '" << magie1 << "' are " << magie1.length() << " caractere\n";
        cout << "   (sau " << magie1.size() << " caractere cu .size())\n";
    
        // 3. GOAL? - "Verificarea Videzii"
        string sacGol = "";
        string sacPlin = "Vrajeala";
    
        cout << "\n3. VERIFICARE GOAL:\n";
        cout << "   sacGol.empty(): " << (sacGol.empty() ? "DA" : "NU") << endl;
        cout << "   sacPlin.empty(): " << (sacPlin.empty() ? "DA" : "NU") << endl;
    
        return 0;
    }

    B. Operații Magice: “Trucurile Magicianului”

    #include <iostream>
    #include <string>
    using namespace std;
    
    int main() {
        cout << "=== OPERAȚII MAGICE cu STRING-URI ===\n\n";
    
        string vrajitor = "Merlin";
        string actiune = "invata";
        string obiect = "magie";
    
        // 1. CONCATENAREA - "Alchimia Cuvintelor"
        // GÂNDEȘTE-TE: Lipirea a două vagoane de tren
        string propozitie = vrajitor + " " + actiune + " " + obiect + ".";
        cout << "1. CONCATENARE (+):\n";
        cout << "   " << propozitie << endl;
    
        // Adăugare la sfârșit - "Extinderea Vagonului"
        propozitie += " Foarte mult!";
        cout << "   Cu +=: " << propozitie << endl;
    
        // 2. COMPARAREA - "Balanța Dreptății"
        // GÂNDEȘTE-TE: Cine e "mai mare" alfabetic?
        string cuv1 = "Ana";
        string cuv2 = "Maria";
        string cuv3 = "Ana";
    
        cout << "\n2. COMPARARE:\n";
        cout << "   '" << cuv1 << "' == '" << cuv3 << "': " 
             << (cuv1 == cuv3 ? "ADEVARAT" : "FALS") << endl;
        cout << "   '" << cuv1 << "' == '" << cuv2 << "': " 
             << (cuv1 == cuv2 ? "ADEVARAT" : "FALS") << endl;
        cout << "   '" << cuv1 << "' < '" << cuv2 << "': " 
             << (cuv1 < cuv2 ? "ADEVARAT" : "FALS") << " (A < M alfabetic)\n";
    
        // 3. ACCES CARACTERE - "Vagonul Specific"
        // GÂNDEȘTE-TE: Caut vagonul numărul X din tren
        string tren = "Express";
    
        cout << "\n3. ACCES CARACTERE:\n";
        cout << "   Trenul: " << tren << endl;
        cout << "   Primul vagon [0]: " << tren[0] << endl;
        cout << "   Al treilea vagon [2]: " << tren[2] << endl;
        cout << "   Ultimul vagon: " << tren[tren.length()-1] << endl;
    
        // Modificare caracter
        tren[0] = 'E';  // Schimbă 'E' în 'E' (rămâne la fel)
        cout << "   După modificare: " << tren << endl;
    
        return 0;
    }

    C. Căutare și Găsire: “Vânătoarea de Comori”

    #include <iostream>
    #include <string>
    using namespace std;
    
    int main() {
        cout << "=== VÂNĂTOAREA DE COMORI în STRING-URI ===\n\n";
    
        string mapa = "Comoara se afla sub copacul mare din padure";
    
        cout << "Harta noastră: \"" << mapa << "\"\n\n";
    
        // 1. FIND - "Detectorul de Metal"
        // GÂNDEȘTE-TE: Caut unde începe cuvântul "comoara"
        size_t pozitie = mapa.find("comoara");
    
        cout << "1. FIND (căutare):\n";
        if(pozitie != string::npos) {  // npos = "Nu am găsit nimic"
            cout << "   Am găsit 'comoara' la poziția: " << pozitie << endl;
        } else {
            cout << "   Nu am găsit comoara :(\n";
        }
    
        // Caută de la o anumită poziție
        pozitie = mapa.find("a", 10);  // Caută 'a' începând cu poziția 10
        cout << "   Prima 'a' după poziția 10: " << pozitie << endl;
    
        // 2. RFIND - "Căutarea Inversă"
        // GÂNDEȘTE-TE: Caut ULTIMA apariție
        pozitie = mapa.rfind("a");
        cout << "\n2. RFIND (căutare inversă):\n";
        cout << "   Ultima 'a' este la: " << pozitie << endl;
    
        // 3. FIND_FIRST_OF - "Orice din Listă"
        // GÂNDEȘTE-TE: Găsește PRIMA vocală
        pozitie = mapa.find_first_of("aeiou");
        cout << "\n3. FIND_FIRST_OF (orice caracter din listă):\n";
        cout << "   Prima vocală este la: " << pozitie << endl;
    
        // 4. FIND_LAST_OF - "Ultimul din Listă"
        pozitie = mapa.find_last_of("aeiou");
        cout << "\n4. FIND_LAST_OF (ultimul din listă):\n";
        cout << "   Ultima vocală este la: " << pozitie << endl;
    
        return 0;
    }

    D. Tăiere și Lipire: “Chirurgia String-urilor”

    #include <iostream>
    #include <string>
    using namespace std;
    
    int main() {
        cout << "=== CHIRURGIA STRING-URILOR ===\n\n";
    
        string pacient = "Acesta este un string lung si interesant";
    
        cout << "Pacientul inițial: \"" << pacient << "\"\n\n";
    
        // 1. SUBSTR - "Extragerea unei Bucați"
        // GÂNDEȘTE-TE: Tai o felie din tortă
        string felie = pacient.substr(8, 10);  // de la pozitia 8, 10 caractere
    
        cout << "1. SUBSTR (extragere):\n";
        cout << "   pacient.substr(8, 10) = \"" << felie << "\"\n";
    
        // 2. REPLACE - "Înlocuirea Magică"
        // GÂNDEȘTE-TE: Înlocuiesc o bucată cu alta
        pacient.replace(8, 10, "a fost");
    
        cout << "\n2. REPLACE (înlocuire):\n";
        cout << "   După replace: \"" << pacient << "\"\n";
    
        // 3. ERASE - "Ștergerea cu Radierul Magic"
        // GÂNDEȘTE-TE: Șterg o parte
        pacient.erase(20, 5);  // șterge 5 caractere începând cu poziția 20
    
        cout << "\n3. ERASE (ștergere):\n";
        cout << "   După erase: \"" << pacient << "\"\n";
    
        // 4. INSERT - "Inserez ceva Nou"
        // GÂNDEȘTE-TE: Bag un vagon nou în tren
        pacient.insert(20, "foarte ");
    
        cout << "\n4. INSERT (inserare):\n";
        cout << "   După insert: \"" << pacient << "\"\n";
    
        return 0;
    }

    E. Transformări: “Metamorfoza String-urilor”

    #include <iostream>
    #include <string>
    #include <algorithm>  // pentru transform
    using namespace std;
    
    int main() {
        cout << "=== METAMORFOZA STRING-URILOR ===\n\n";
    
        string animal = "Un Dragon magic zboara sus";
    
        cout << "Animalul inițial: \"" << animal << "\"\n\n";
    
        // 1. TRANSFORM - "Schimbarea Formei"
        // GÂNDEȘTE-TE: Transform toate literele în majuscule
    
        string dragonMare = animal;
        transform(dragonMare.begin(), dragonMare.end(), dragonMare.begin(), ::toupper);
    
        cout << "1. TRANSFORM (majuscule):\n";
        cout << "   TOATE MAJUSCULE: \"" << dragonMare << "\"\n";
    
        // Transform în minuscule
        string dragonMic = animal;
        transform(dragonMic.begin(), dragonMic.end(), dragonMic.begin(), ::tolower);
    
        cout << "   toate minuscule: \"" << dragonMic << "\"\n";
    
        // 2. SWAP - "Schimbul Magicianilor"
        // GÂNDEȘTE-TE: Schimb conținutul a două cutii
        string cutie1 = "Vrajeala";
        string cutie2 = "Magie";
    
        cout << "\n2. SWAP (schimb):\n";
        cout << "   Înainte: cutie1 = \"" << cutie1 << "\", cutie2 = \"" << cutie2 << "\"\n";
    
        cutie1.swap(cutie2);
    
        cout << "   După swap: cutie1 = \"" << cutie1 << "\", cutie2 = \"" << cutie2 << "\"\n";
    
        return 0;
    }

    Partea 2: Pascal – Vrăjitorul Clasic

    program MagiaStringurilor;
    uses sysutils;  { Cutia noastră de instrumente magice }
    
    var
      vraja, incantatie, rezultat: string;
      poz: integer;
    
    begin
      writeln('=== VRĂJILE STRING-URILOR în PASCAL ===');
      writeln;
    
      { 1. CREARE ȘI LUNGIME - "Învățământul de bază" }
      vraja := 'Abracadabra';
      incantatie := 'Hocus Pocus';
    
      writeln('1. CREARE ȘI LUNGIME:');
      writeln('   vraja = "', vraja, '"');
      writeln('   Lungimea: ', length(vraja), ' caractere');
      writeln('   incantatie = "', incantatie, '"');
    
      { 2. CONCATENARE - "Alchimia Pascal" }
      rezultat := vraja + ' ' + incantatie + '!';
      writeln;
      writeln('2. CONCATENARE:');
      writeln('   ', rezultat);
    
      { 3. COMPARARE - "Balanța Vrăjitorului" }
      writeln;
      writeln('3. COMPARARE:');
      writeln('   "', vraja, '" = "', vraja, '": ', vraja = vraja);
      writeln('   "', vraja, '" < "', incantatie, '": ', vraja < incantatie);
    
      { 4. ACCES CARACTERE - "Vagonul Specific" }
      { ATENȚIE: În Pascal indexarea începe de la 1! }
      writeln;
      writeln('4. ACCES CARACTERE (index de la 1):');
      writeln('   vraja[1] = ', vraja[1]);
      writeln('   vraja[3] = ', vraja[3]);
      writeln('   Ultimul: vraja[', length(vraja), '] = ', vraja[length(vraja)]);
    
      { 5. CĂUTARE - "Vânătoarea de Vrăji" }
      vraja := 'Comoara se afla sub copacul mare';
      poz := pos('copac', vraja);
    
      writeln;
      writeln('5. CĂUTARE (pos):');
      writeln('   "copac" in "', vraja, '" -> pozitia ', poz);
    
      { 6. EXTRAGERE - "Decuparea Vrăjii" }
      rezultat := copy(vraja, 20, 6);
      writeln;
      writeln('6. EXTRAGERE (copy):');
      writeln('   copy("', vraja, '", 20, 6) = "', rezultat, '"');
    
      { 7. ȘTERGERE - "Dispariția Vrăjită" }
      delete(vraja, 20, 6);
      writeln;
      writeln('7. ȘTERGERE (delete):');
      writeln('   după delete(20,6): "', vraja, '"');
    
      { 8. INSERARE - "Apariția Magică" }
      insert('inalt ', vraja, 20);
      writeln;
      writeln('8. INSERARE (insert):');
      writeln('   după insert("inalt ", 20): "', vraja, '"');
    
      { 9. TRANSFORMĂRI - "Metamorfoza" }
      writeln;
      writeln('9. TRANSFORMĂRI:');
      writeln('   LowerCase("VRAJITOR"): ', LowerCase('VRAJITOR'));
      writeln('   UpperCase("vrajitor"): ', UpperCase('vrajitor'));
    
      { 10. FORMATARE - "Arta Frumuseții" }
      writeln;
      writeln('10. FORMATARE:');
      writeln('   Format: ', Format('%s are %d mere magice', ['Vrajitorul', 7]));
    end.

    Tabel Magic Comparativ: C++ vs Pascal

    Operație MagicaC++ (<string>)Pascal
    Crearestring s = "magie";s := 'magie';
    Lungimes.length() sau s.size()length(s)
    Concatenares1 + s2 sau s1 += s2s1 + s2
    Comparares1 == s2, s1 < s2s1 = s2, s1 < s2
    Căutares.find("ceva")pos('ceva', s)
    Extrageres.substr(poz, n)copy(s, poz, n)
    Ștergeres.erase(poz, n)delete(s, poz, n)
    Inserares.insert(poz, "text")insert('text', s, poz)
    Majusculetransform(..., ::toupper)UpperCase(s)
    Minusculetransform(..., ::tolower)LowerCase(s)

    Reguli de Aur pentru Magia String-urilor

    Pentru C++:

    // 1. FIND întotdeauna verifică cu string::npos
    if (text.find("comoara") != string::npos) {
        cout << "Am gasit comoara!";
    }
    
    // 2. SUBSTR - primește (pozitie, lungime)
    string bucata = text.substr(3, 5);  // 5 caractere începând cu poziția 3
    
    // 3. La INSERT, ERASE, REPLACE - prima poziție e indexul
    text.insert(5, "AAA");  // inserează "AAA" la poziția 5
    
    // 4. Operatorul + pentru concatenare e cel mai ușor
    string complet = "Buna " + nume + "!";

    Pentru Pascal:

    { 1. Indexarea începe de la 1, nu de la 0! }
    s := 'Salut';
    writeln(s[1]);  { afișează 'S' }
    writeln(s[3]);  { afișează 'l' }
    
    { 2. POS întoarce 0 dacă nu găsește }
    poz := pos('magie', s);
    if poz > 0 then
        writeln('Gasit la pozitia ', poz);
    
    { 3. COPY primește (sursa, pozitie, lungime) }
    bucata := copy(s, 2, 3);  { 3 caractere începând cu poziția 2 }

    Exercițiu Final: “Vrăjitorul Începător”

    #include <iostream>
    #include <string>
    using namespace std;
    
    int main() {
        cout << "=== EXAMENUL VRĂJITORULUI ÎNCEPĂTOR ===\n\n";
    
        // Problema 1: Inversează un nume
        string numeIntreg = "Merlin Vrajitorul";
    
        // Găsește spațiul
        size_t spatiu = numeIntreg.find(' ');
    
        if (spatiu != string::npos) {
            string prenume = numeIntreg.substr(0, spatiu);
            string nume = numeIntreg.substr(spatiu + 1);
    
            cout << "1. Nume inversat:\n";
            cout << "   Original: " << numeIntreg << endl;
            cout << "   Inversat: " << nume << " " << prenume << endl;
        }
    
        // Problema 2: Creează un username
        string numeComplet = "Ana Maria Popescu";
        string username = "";
    
        // Ia prima literă din fiecare nume
        username += tolower(numeComplet[0]);  // 'a'
    
        for (size_t i = 0; i < numeComplet.length(); i++) {
            if (numeComplet[i] == ' ') {
                username += tolower(numeComplet[i + 1]);
            }
        }
    
        // Adaugă ultimul nume
        size_t ultimSpatiu = numeComplet.find_last_of(' ');
        if (ultimSpatiu != string::npos) {
            string ultimNume = numeComplet.substr(ultimSpatiu + 1);
            transform(ultimNume.begin(), ultimNume.end(), ultimNume.begin(), ::tolower);
            username += ultimNume;
        }
    
        cout << "\n2. Username generat:\n";
        cout << "   Nume complet: " << numeComplet << endl;
        cout << "   Username: " << username << endl;
    
        return 0;
    }

    Concluzie Magică:

    Fie că folosești C++ sau Pascal, string-urile sunt ca un set de instrumente magice. Învață să le folosești bine, și vei putea face orice cu textul în programele tale! 🧙‍♂️✨

  • Șiruri de Caractere (String-uri): “Cuvintele și Frazele” Calculatorului

    Bun, hai să vorbim despre unul dintre cele mai importante și folosite tipuri de date din programare: ȘIRURILE DE CARACTERE (String-urile). Nu sunt doar texte (cuvânt simplu) și litere. Sunt modul în care calculatorul înțelege cuvintele, frazele, numele, adresele – tot ce ține de limbaj uman.

    1. Ce este un Șir de Caractere? “Un Tren de Caractere”

    Gândește-te la un șir de caractere ca la un tren unde fiecare vagon este o literă, cifră sau simbol:

    • Șir: “Salut”
    • Caractere: ‘S’ ‘a’ ‘l’ ‘u’ ‘t’
    • Terminator: ‘\0’ (caracterul invizibil de la sfârșit)

    Analogie cu un Cuvânt Într-o Cutie:

    Cutia poate conține: S a l u t \0 \0 \0 \0 \0
    Unde \0 e terminatorul care spune “aici se termină cuvântul”

    2. Cum se Declară Șirurile în C++?

    Metoda 1: Ca vector de caractere (mod clasic C)

    #include <iostream>
    using namespace std;
    
    int main() {
        // Declarare cu dimensiune fixă
        char nume[20];  // Poate stoca 19 caractere + terminator
    
        // Declarare cu inițializare
        char mesaj[] = "Buna ziua!";  // Compilatorul calculează dimensiunea
    
        // Dimensiune explicită
        char salut[10] = "Salut";  // 5 caractere + \0 + spațiu liber
    
        return 0;
    }

    Metoda 2: Ca string (mod modern C++)

    #include <iostream>
    #include <string>  // TREBUIE inclus pentru string
    using namespace std;
    
    int main() {
        string nume = "Ana";
        string prenume("Maria");  // Alt mod de inițializare
        string salut = "Buna, " + nume + "!";  // Concatenare ușoară
    
        return 0;
    }

    3. Diferența dintre char[] și string

    #include <iostream>
    #include <string>
    using namespace std;
    
    int main() {
        cout << "=== COMPARATIE char[] vs string ===\n\n";
    
        cout << "char nume[20]:\n";
        cout << "- Dimensiune fixă (trebuie să știi maximul)\n";
        cout << "- Mai rapid, folosește mai puțină memorie\n";
        cout << "- Funcții limitate\n";
        cout << "- Terminator \\0 obligatoriu\n\n";
    
        cout << "string nume:\n";
        cout << "- Dimensiune dinamică (se ajustează)\n";
        cout << "- Mai multe funcții utile\n";
        cout << "- Ușor de folosit\n";
        cout << "- Folosește mai multă memorie\n";
    
        return 0;
    }

    4. Cum se Citește un Șir de la Tastatură?

    4.1 Pentru char[] (vector de caractere)

    #include <iostream>
    using namespace std;
    
    int main() {
        char nume[50];
    
        // Metoda 1: cin (se oprește la spațiu)
        cout << "Introdu numele (cin): ";
        cin >> nume;  // "Ana Maria" → va citi doar "Ana"
    
        cout << "Ai introdus: " << nume << endl;
    
        // Metoda 2: cin.getline() (citeste tot rândul)
        cout << "\nIntrodu numele complet (cin.getline): ";
        cin.ignore();  // Curată buffer-ul
        cin.getline(nume, 50);  // "Ana Maria" → "Ana Maria"
    
        cout << "Ai introdus: " << nume << endl;
    
        return 0;
    }

    4.2 Pentru string

    #include <iostream>
    #include <string>
    using namespace std;
    
    int main() {
        string nume;
    
        // Metoda 1: cin (se oprește la spațiu)
        cout << "Introdu numele (cin): ";
        cin >> nume;  // "Ana Maria" → "Ana"
    
        cout << "Ai introdus: " << nume << endl;
    
        // Metoda 2: getline() (citeste tot rândul)
        cout << "\nIntrodu numele complet (getline): ";
        cin.ignore();  // Curată buffer-ul!
        getline(cin, nume);  // "Ana Maria" → "Ana Maria"
    
        cout << "Ai introdus: " << nume << endl;
    
        return 0;
    }

    5. Cum se Afișează Șirurile?

    #include <iostream>
    #include <string>
    using namespace std;
    
    int main() {
        char numeChar[] = "Ana";
        string numeString = "Maria";
    
        // Afișare simplă
        cout << "Salut, " << numeChar << "!" << endl;
        cout << "Salut, " << numeString << "!" << endl;
    
        // Afișare caracter cu caracter (doar pentru char[])
        cout << "\nCaracterele din \"" << numeChar << "\": ";
        for(int i = 0; numeChar[i] != '\0'; i++) {
            cout << numeChar[i] << "-";
        }
        cout << endl;
    
        return 0;
    }

    6. Operații de Bază cu String-uri

    6.1 Lungimea unui șir

    #include <iostream>
    #include <string>
    #include <cstring>  // pentru strlen()
    using namespace std;
    
    int main() {
        char textChar[] = "Salut";
        string textString = "Buna ziua";
    
        // Pentru char[]: strlen()
        cout << "Lungime char[]: " << strlen(textChar) << endl;
    
        // Pentru string: .length() sau .size()
        cout << "Lungime string: " << textString.length() << endl;
        cout << "Lungime string: " << textString.size() << endl;
    
        return 0;
    }

    6.2 Concatenare (lipirea a două șiruri)

    #include <iostream>
    #include <string>
    #include <cstring>  // pentru strcat()
    using namespace std;
    
    int main() {
        // Pentru char[]: strcat()
        char nume[50] = "Ana ";
        char prenume[] = "Maria";
        strcat(nume, prenume);  // nume devine "Ana Maria"
        cout << "char[] concatenat: " << nume << endl;
    
        // Pentru string: operatorul + sau .append()
        string numeStr = "Ana ";
        string prenumeStr = "Maria";
        string complet = numeStr + prenumeStr;  // "Ana Maria"
        cout << "string concatenat: " << complet << endl;
    
        return 0;
    }

    6.3 Compararea a două șiruri

    #include <iostream>
    #include <string>
    #include <cstring>  // pentru strcmp()
    using namespace std;
    
    int main() {
        char a[] = "Ana";
        char b[] = "Ana";
    
        // Pentru char[]: strcmp()
        if(strcmp(a, b) == 0) {
            cout << "char[]: Sunt egale!" << endl;
        } else {
            cout << "char[]: Sunt diferite!" << endl;
        }
    
        // Pentru string: operatorul ==
        string x = "Ana";
        string y = "Maria";
    
        if(x == y) {
            cout << "string: Sunt egale!" << endl;
        } else {
            cout << "string: Sunt diferite!" << endl;
        }
    
        return 0;
    }

    7. Transformări ale Șirurilor

    7.1 Majuscule/Miniscule

    #include <iostream>
    #include <cctype>  // pentru toupper(), tolower()
    #include <string>
    using namespace std;
    
    int main() {
        char text[] = "Salut Lume";
    
        // Transformă în majuscule
        cout << "Majuscule: ";
        for(int i = 0; text[i] != '\0'; i++) {
            cout << (char)toupper(text[i]);
        }
        cout << endl;
    
        // Transformă în minuscule
        cout << "Minuscule: ";
        for(int i = 0; text[i] != '\0'; i++) {
            cout << (char)tolower(text[i]);
        }
        cout << endl;
    
        return 0;
    }

    7.2 Inversarea unui șir

    #include <iostream>
    #include <cstring>
    using namespace std;
    
    int main() {
        char text[] = "salut";
        int lungime = strlen(text);
    
        cout << "Original: " << text << endl;
    
        // Inversează șirul
        for(int i = 0; i < lungime/2; i++) {
            char temp = text[i];
            text[i] = text[lungime-1-i];
            text[lungime-1-i] = temp;
        }
    
        cout << "Inversat: " << text << endl;
    
        return 0;
    }

    8. Probleme Practice

    Problema 1: Verifică dacă un șir este palindrom

    #include <iostream>
    #include <cstring>
    using namespace std;
    
    int main() {
        char text[] = "capac";
        int lungime = strlen(text);
        bool palindrom = true;
    
        for(int i = 0; i < lungime/2; i++) {
            if(text[i] != text[lungime-1-i]) {
                palindrom = false;
                break;
            }
        }
    
        if(palindrom) {
            cout << "\"" << text << "\" este palindrom!" << endl;
        } else {
            cout << "\"" << text << "\" NU este palindrom!" << endl;
        }
    
        return 0;
    }

    Problema 2: Numără vocalele dintr-un șir

    #include <iostream>
    #include <cstring>
    #include <cctype>
    using namespace std;
    
    int main() {
        char text[] = "Salut lume!";
        int vocale = 0;
    
        for(int i = 0; text[i] != '\0'; i++) {
            char c = tolower(text[i]);  // Transformă în minuscule
    
            if(c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') {
                vocale++;
            }
        }
    
        cout << "In \"" << text << "\" sunt " << vocale << " vocale" << endl;
    
        return 0;
    }

    Problema 3: Extrage numele din inițială

    #include <iostream>
    #include <string>
    using namespace std;
    
    int main() {
        string numeComplet;
    
        cout << "Introdu numele complet: ";
        getline(cin, numeComplet);
    
        // Găsește primul spațiu
        size_t pozitieSpatiu = numeComplet.find(' ');
    
        if(pozitieSpatiu != string::npos) {
            string prenume = numeComplet.substr(0, pozitieSpatiu);
            string nume = numeComplet.substr(pozitieSpatiu + 1);
    
            cout << "Prenume: " << prenume << endl;
            cout << "Nume: " << nume << endl;
        } else {
            cout << "Ai introdus doar un nume!" << endl;
        }
    
        return 0;
    }

    9. Citirea Corectă a Mai Multor Șiruri

    GREȘIT (problema comună):

    #include <iostream>
    #include <string>
    using namespace std;
    
    int main() {
        int varsta;
        string nume;
    
        cout << "Varsta: ";
        cin >> varsta;
    
        cout << "Nume: ";
        getline(cin, nume);  // PROBLEMĂ! Citește enter-ul rămas
    
        cout << "Numele tau este: " << nume << endl;
    
        return 0;
    }

    CORECT:

    #include <iostream>
    #include <string>
    using namespace std;
    
    int main() {
        int varsta;
        string nume;
    
        cout << "Varsta: ";
        cin >> varsta;
    
        cin.ignore();  // CURĂȚĂ buffer-ul!
    
        cout << "Nume: ";
        getline(cin, nume);
    
        cout << "Numele tau este: " << nume << endl;
    
        return 0;
    }

    10. Reguli Importante

    Pentru char[]:

    1. Dimensiunea trebuie să fie suficient de mare (caractere + \0)
    2. Terminatorul \0 marchează sfârșitul
    3. Folosește funcții din <cstring> (strlen, strcpy, strcat, strcmp)
    4. cin se oprește la spațiu, cin.getline() citește linia întreagă

    Pentru string:

    1. Dimensiunea se ajustează automat
    2. Folosește <string> și metodele sale (.length(), .size(), .find(), etc.)
    3. Operatorul + concatenă, == compară
    4. cin se oprește la spațiu, getline() citește linia întreagă

    În concluzie:

    • char[] = mai rapid, mai puțină memorie, dar mai greu de folosit
    • string = mai ușor de folosit, mai multe funcții, dar mai multă memorie

    Regula de aur:

    1. Pentru exerciții simple: folosește string
    2. Pentru optimizare maximă: folosește char[]
    3. NU UITA: cin.ignore() când alternezi cin >> cu getline()
  • Metode de Căutare: Secvențială și Binară

    Bun, hai să vorbim despre cele două metode fundamentale de căutare: CĂUTAREA SECVENȚIALĂ și CĂUTAREA BINARĂ. Nu sunt doar algoritmi – sunt două moduri complet diferite de a gândi și de a rezolva problema “găsește acul în carul cu fân”.

    1. Problema de Bază: “Găsește Cheia în Grămadă”

    Ipoteză: Ai o colecție de elemente și vrei să găsești un anumit element.

    Exemplu concret:

    Vector: [5, 2, 8, 1, 9, 3, 7]
    Vrem să găsim: 9

    2. Căutarea Secvențială (Liniară): “Verifică Toate, Una Câte Una”

    Strategie: Începi de la început și verifici fiecare element până îl găsești sau ajungi la sfârșit.

    #include <iostream>
    using namespace std;
    
    int main() {
        int v[] = {5, 2, 8, 1, 9, 3, 7};
        int n = 7;
        int cautat = 9;
    
        bool gasit = false;
        int pozitie = -1;
    
        for(int i = 0; i < n; i++) {
            if(v[i] == cautat) {
                gasit = true;
                pozitie = i;
                break;  // Opresc imediat ce l-am găsit
            }
        }
    
        if(gasit) {
            cout << "Am gasit " << cautat << " pe pozitia " << pozitie << endl;
        } else {
            cout << "Nu am gasit " << cautat << " in vector!" << endl;
        }
    
        return 0;
    }

    Cum funcționează pas cu pas:

    Caut 9 în [5, 2, 8, 1, 9, 3, 7]
    
    Pas 1: v[0] = 5 → nu e 9
    Pas 2: v[1] = 2 → nu e 9  
    Pas 3: v[2] = 8 → nu e 9
    Pas 4: v[3] = 1 → nu e 9
    Pas 5: v[4] = 9 → DA! GĂSIT!

    Caracteristici căutare secvențială:

    • Funcționează pe orice vector (nesortat sau sortat)
    • Simplu de implementat
    • În cel mai rău caz: verifică toate elementele
    • Complexitate: O(n)

    3. Căutarea Binară: “Împarte și Câștigă”

    ATENȚIE: Funcționează DOAR pe vectori SORTAȚI!

    Strategie: Împarte vectorul în jumătate, decide în care jumătate se află elementul, repetă.

    #include <iostream>
    using namespace std;
    
    int main() {
        // VECTOR SORTAT!
        int v[] = {1, 2, 3, 5, 7, 8, 9};
        int n = 7;
        int cautat = 5;
    
        int stanga = 0;
        int dreapta = n - 1;
        bool gasit = false;
        int pozitie = -1;
    
        while(stanga <= dreapta) {
            int mijloc = (stanga + dreapta) / 2;
    
            cout << "Caut intre pozitiile " << stanga << " si " << dreapta 
                 << " (mijloc=" << mijloc << ", valoare=" << v[mijloc] << ")" << endl;
    
            if(v[mijloc] == cautat) {
                gasit = true;
                pozitie = mijloc;
                break;
            }
    
            if(v[mijloc] < cautat) {
                stanga = mijloc + 1;  // Caut în dreapta
                cout << "  → Merg la dreapta" << endl;
            } else {
                dreapta = mijloc - 1;  // Caut în stânga
                cout << "  → Merg la stanga" << endl;
            }
        }
    
        if(gasit) {
            cout << "\nAm gasit " << cautat << " pe pozitia " << pozitie << endl;
        } else {
            cout << "\nNu am gasit " << cautat << " in vector!" << endl;
        }
    
        return 0;
    }

    Cum funcționează pas cu pas:

    Caut 5 în [1, 2, 3, 5, 7, 8, 9] (SORTAT!)
    
    Pas 1: stanga=0, dreapta=6, mijloc=3, v[3]=5 → GĂSIT! (doar 1 pas!)

    Un exemplu mai lung:

    Caut 7 în [1, 2, 3, 5, 7, 8, 9]
    
    Pas 1: stanga=0, dreapta=6, mijloc=3, v[3]=5
           5 < 7 → merg la dreapta
    
    Pas 2: stanga=4, dreapta=6, mijloc=5, v[5]=8  
           8 > 7 → merg la stânga
    
    Pas 3: stanga=4, dreapta=4, mijloc=4, v[4]=7 → GĂSIT!

    4. Compararea Cele Două Metode

    #include <iostream>
    using namespace std;
    
    int main() {
        cout << "=== COMPARATIE CĂUTARE SECVENȚIALĂ vs BINARĂ ===\n\n";
    
        cout << "CĂUTAREA SECVENȚIALĂ:\n";
        cout << "• Funcționează pe orice vector (nesortat sau sortat)\n";
        cout << "• Simplu de implementat\n";
        cout << "• În cel mai rău caz: verifică TOATE elementele\n";
        cout << "• Complexitate: O(n)\n";
        cout << "• Pentru 1.000.000 elemente: maxim 1.000.000 verificări\n\n";
    
        cout << "CĂUTAREA BINARĂ:\n";
        cout << "• Funcționează DOAR pe vectori SORTAȚI\n";
        cout << "• Mai complex de implementat\n";
        cout << "• În cel mai rău caz: verifică log₂(n) elemente\n";
        cout << "• Complexitate: O(log n)\n";
        cout << "• Pentru 1.000.000 elemente: maxim 20 verificări!\n";
    
        return 0;
    }

    5. Tabel Comparativ

    CaracteristicăCăutare SecvențialăCăutare Binară
    Vector necesarOrice vectorDOAR vectori SORTAȚI
    ImplementareSimplăMai complexă
    ComplexitateO(n)O(log n)
    Timp 1.000.000 elem~500.000 verificări (în medie)~20 verificări
    Când să foloseștiVectori nesortați sau miciVectori sortați mari

    6. Variante ale Algoritmilor

    6.1 Căutare secvențială cu poziția tuturor aparițiilor

    #include <iostream>
    using namespace std;
    
    int main() {
        int v[] = {5, 2, 5, 1, 5, 3, 5};
        int n = 7;
        int cautat = 5;
    
        cout << "Caut toate aparitiile lui " << cautat << ":\n";
    
        for(int i = 0; i < n; i++) {
            if(v[i] == cautat) {
                cout << "Gasit pe pozitia " << i << endl;
            }
        }
    
        return 0;
    }

    6.2 Căutare binară recursivă

    #include <iostream>
    using namespace std;
    
    int cautareBinaraRec(int v[], int stanga, int dreapta, int cautat) {
        if(stanga > dreapta) {
            return -1;  // Nu am găsit
        }
    
        int mijloc = (stanga + dreapta) / 2;
    
        if(v[mijloc] == cautat) {
            return mijloc;  // Am găsit!
        }
    
        if(v[mijloc] < cautat) {
            return cautareBinaraRec(v, mijloc + 1, dreapta, cautat);
        } else {
            return cautareBinaraRec(v, stanga, mijloc - 1, cautat);
        }
    }
    
    int main() {
        int v[] = {1, 2, 3, 5, 7, 8, 9};
        int n = 7;
    
        int poz = cautareBinaraRec(v, 0, n-1, 5);
        cout << "Gasit pe pozitia: " << poz << endl;
    
        return 0;
    }

    7. Când Să Folosești Care?

    Folosește căutarea SECVENȚIALĂ când:

    1. Vectorul e nesortat
    2. Vectorul e mic (sub 100 elemente)
    3. Cauți toate aparițiile unui element
    4. Vectorul se modifică des (nu merită să-l sorți)

    Folosește căutarea BINARĂ când:

    1. Vectorul e sortat (sau poate fi sortat)
    2. Vectorul e mare (peste 1000 elemente)
    3. Faci multe căutări pe același vector
    4. Viteza e importantă

    8. Demonstrație de Performanță

    #include <iostream>
    #include <ctime>
    using namespace std;
    
    int main() {
        const int N = 1000000;  // 1 milion de elemente!
        int* v = new int[N];
    
        // Generez un vector sortat
        for(int i = 0; i < N; i++) {
            v[i] = i * 2;  // Numere pare: 0, 2, 4, 6, ...
        }
    
        int cautat = 500000;  // Caut un element din mijloc
    
        // Test căutare secvențială
        cout << "Caut " << cautat << " in " << N << " elemente:\n\n";
    
        clock_t start = clock();
    
        // Căutare secvențială
        bool gasitSecvential = false;
        for(int i = 0; i < N; i++) {
            if(v[i] == cautat) {
                gasitSecvential = true;
                break;
            }
        }
    
        clock_t end = clock();
        double timpSecvential = double(end - start) / CLOCKS_PER_SEC;
    
        cout << "Cautare secventiala: " << timpSecvential << " secunde\n";
    
        // Test căutare binară
        start = clock();
    
        // Căutare binară
        bool gasitBinar = false;
        int stanga = 0, dreapta = N - 1;
    
        while(stanga <= dreapta) {
            int mijloc = (stanga + dreapta) / 2;
    
            if(v[mijloc] == cautat) {
                gasitBinar = true;
                break;
            }
    
            if(v[mijloc] < cautat) {
                stanga = mijloc + 1;
            } else {
                dreapta = mijloc - 1;
            }
        }
    
        end = clock();
        double timpBinar = double(end - start) / CLOCKS_PER_SEC;
    
        cout << "Cautare binara:      " << timpBinar << " secunde\n";
    
        if(timpSecvential > 0) {
            cout << "\nBINARA e de " << timpSecvential/timpBinar << "x mai rapida!\n";
        }
    
        delete[] v;
        return 0;
    }

    9. Probleme Practice

    Problema 1: Căutare în vector nesortat (doar secvențială)

    #include <iostream>
    using namespace std;
    
    int main() {
        int v[] = {5, 2, 8, 1, 9, 3, 7};  // NESORTAT
        int n = 7;
        int cautat;
    
        cout << "Ce numar cauti? ";
        cin >> cautat;
    
        bool gasit = false;
    
        for(int i = 0; i < n; i++) {
            if(v[i] == cautat) {
                cout << "Gasit pe pozitia " << i << endl;
                gasit = true;
                break;
            }
        }
    
        if(!gasit) {
            cout << "Nu am gasit numarul!" << endl;
        }
    
        return 0;
    }

    Problema 2: Verifică dacă un vector e sortat (pentru căutare binară)

    #include <iostream>
    using namespace std;
    
    bool esteSortat(int v[], int n) {
        for(int i = 0; i < n-1; i++) {
            if(v[i] > v[i+1]) {
                return false;  // NU e sortat
            }
        }
        return true;  // E sortat
    }
    
    int main() {
        int v[] = {1, 2, 3, 5, 7, 8, 9};
        int n = 7;
    
        if(esteSortat(v, n)) {
            cout << "Vectorul este sortat - pot folosi cautare binara!\n";
        } else {
            cout << "Vectorul NU este sortat - folosesc cautare secventiala!\n";
        }
    
        return 0;
    }

    Problema 3: Căutare binară cu verificare la limită

    #include <iostream>
    using namespace std;
    
    int main() {
        int v[] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
        int n = 10;
    
        int cautat;
        cout << "Ce numar cauti? ";
        cin >> cautat;
    
        // Verific dacă numărul se află în intervalul vectorului
        if(cautat < v[0] || cautat > v[n-1]) {
            cout << "Numarul nu se afla in vector!" << endl;
            return 0;
        }
    
        // Căutare binară normală...
    
        return 0;
    }

    10. Exerciții de Înțelegere

    Exercițiul 1: Completează căutarea secvențială

    int v[] = {5, 2, 8, 1, 9};
    int n = 5;
    int cautat = 8;
    bool gasit = false;
    
    for(int i = 0; i < n; i++) {
        if(/* condiție */) {
            gasit = true;
            cout << "Gasit pe pozitia " << /* ce pui aici? */;
            break;
        }
    }

    Soluție:

    if(v[i] == cautat) {
        // ...
        cout << "Gasit pe pozitia " << i;
    }

    Exercițiul 2: Ce face acest cod?

    int stanga = 0, dreapta = n-1;
    while(stanga <= dreapta) {
        int mijloc = (stanga + dreapta) / 2;
        if(v[mijloc] == x) return mijloc;
        if(v[mijloc] < x) stanga = mijloc + 1;
        else dreapta = mijloc - 1;
    }
    return -1;

    Răspuns: Este algoritmul de căutare binară.

    Exercițiul 3: Când căutarea binară NU funcționează?

    int v[] = {5, 2, 8, 1, 9};  // NESORTAT
    // Căutare binară aici ar da rezultate greșite!

    Schema de Decizie: Ce Algoritm Să Folosești

    Ai un vector și vrei să cauți un element:
    
    ┌─────────────────────────────────────┐
    │ Vectorul e sortat?                   │
    │         ├─── DA ───► Folosește BINARĂ│
    │         NO                           │
    │         ▼                            │
    │ Vectorul e mic (<100)?               │
    │         ├─── DA ───► Folosește SECVENȚIALĂ│
    │         NO                           │
    │         ▼                            │
    │ Vrei să-l sorți pentru multe căutări?│
    │         ├─── DA ───► Sortează + BINARĂ│
    │         NO                           │
    │         ▼                            │
    │ Folosește SECVENȚIALĂ                │
    └─────────────────────────────────────┘

    În concluzie:

    • Căutarea secvențială = simplă, merge mereu, dar lentă pentru vectori mari
    • Căutarea binară = rapidă, dar merge doar pe vectori sortați

    Regula de aur:

    • Vector nesortat sau mic → secvențială
    • Vector sortat și mare → binară
    • Dacă faci multe căutări pe un vector, merită să-l sorți o dată și apoi să folosești căutarea binară
  • Interclasare: “Unirea a Două Trenuri Sortate”

    Bun, hai să vorbim despre un algoritm elegant și extrem de util: INTERCLASAREA. Nu e doar despre unire (cuvânt simplu) și combinare. E despre cum îmbinăm două liste deja sortate într-una singură, păstrând ordinea. E un algoritm atât de important încât e piatra de temelie a unuia dintre cei mai eficienți algoritmi de sortare: Merge Sort.

    1. Ce este Interclasarea? “Lipirea a Două Listări Telefonice”

    Gândește-te la interclasare ca la unirea a două agende telefonice deja sortate alfabetic:

    • Ai agenda A: Ana, Cristi, Maria
    • Ai agenda B: Bogdan, Dan, Elena
    • Rezultat: Ana, Bogdan, Cristi, Dan, Elena, Maria

    Regula de bază: Interclasarea funcționează DOAR pe vectori SORTAȚI!

    2. Cum Funcționează Algoritmul? “Compară și Alege”

    Ideea principală: Compară primul element din fiecare vector, ia-l pe cel mai mic, avansează în vectorul respectiv, repetă.

    Analogie cu două cozi la casă:

    Ai două cozi sortate după vârstă (cea mai tânără în față):

    • Coada A: 10 ani, 15 ani, 20 ani
    • Coada B: 12 ani, 18 ani, 22 ani

    Interclasarea: ia pe rând cei mai tineri din fiecare coadă:
    10 (din A), 12 (din B), 15 (din A), 18 (din B), 20 (din A), 22 (din B)

    3. Algoritmul de Interclasare de Bază

    #include <iostream>
    using namespace std;
    
    int main() {
        // Două vectori SORTAȚI
        int A[] = {1, 3, 5, 7};
        int B[] = {2, 4, 6, 8};
    
        int nA = 4;  // Dimensiunea lui A
        int nB = 4;  // Dimensiunea lui B
    
        // Vectorul rezultat (are dimensiunea nA + nB)
        int C[8];
    
        int i = 0;  // Index pentru A
        int j = 0;  // Index pentru B  
        int k = 0;  // Index pentru C
    
        // Interclasare: compară și alege
        while(i < nA && j < nB) {
            if(A[i] < B[j]) {
                C[k] = A[i];
                i++;
            } else {
                C[k] = B[j];
                j++;
            }
            k++;
        }
    
        // Dacă au rămas elemente în A, le copiem
        while(i < nA) {
            C[k] = A[i];
            i++;
            k++;
        }
    
        // Dacă au rămas elemente în B, le copiem
        while(j < nB) {
            C[k] = B[j];
            j++;
            k++;
        }
    
        // Afișare rezultat
        cout << "Vectorul A: ";
        for(int i = 0; i < nA; i++) cout << A[i] << " ";
    
        cout << "\nVectorul B: ";
        for(int i = 0; i < nB; i++) cout << B[i] << " ";
    
        cout << "\nVectorul interclasat C: ";
        for(int i = 0; i < nA + nB; i++) cout << C[i] << " ";
    
        return 0;
    }

    Ce se întâmplă pas cu pas:

    A: [1, 3, 5, 7]     B: [2, 4, 6, 8]     C: []
    
    Pas 1: Compar 1 și 2 → ia 1 (A), C=[1]
    Pas 2: Compar 3 și 2 → ia 2 (B), C=[1,2]  
    Pas 3: Compar 3 și 4 → ia 3 (A), C=[1,2,3]
    Pas 4: Compar 5 și 4 → ia 4 (B), C=[1,2,3,4]
    Pas 5: Compar 5 și 6 → ia 5 (A), C=[1,2,3,4,5]
    Pas 6: Compar 7 și 6 → ia 6 (B), C=[1,2,3,4,5,6]
    Pas 7: Compar 7 și 8 → ia 7 (A), C=[1,2,3,4,5,6,7]
    Pas 8: Rămâne 8 din B → C=[1,2,3,4,5,6,7,8]

    4. Variante ale Algoritmului

    4.1 Interclasare cu elemente duplicate

    #include <iostream>
    using namespace std;
    
    int main() {
        int A[] = {1, 3, 3, 5};
        int B[] = {2, 3, 4, 6};
        int nA = 4, nB = 4;
    
        int C[8];
        int i = 0, j = 0, k = 0;
    
        while(i < nA && j < nB) {
            if(A[i] <= B[j]) {  // Folosim <= pentru duplicate
                C[k] = A[i];
                i++;
            } else {
                C[k] = B[j];
                j++;
            }
            k++;
        }
    
        // Copiere resturi...
    
        cout << "Cu duplicate: ";
        for(int i = 0; i < 8; i++) cout << C[i] << " ";
    
        return 0;
    }

    4.2 Interclasare descrescătoare

    #include <iostream>
    using namespace std;
    
    int main() {
        int A[] = {7, 5, 3, 1};  // SORTAT descrescător
        int B[] = {8, 6, 4, 2};  // SORTAT descrescător
        int nA = 4, nB = 4;
    
        int C[8];
        int i = 0, j = 0, k = 0;
    
        // Schimbăm < cu > pentru descrescător
        while(i < nA && j < nB) {
            if(A[i] > B[j]) {  // > în loc de <
                C[k] = A[i];
                i++;
            } else {
                C[k] = B[j];
                j++;
            }
            k++;
        }
    
        // Copiere resturi...
    
        cout << "Descrescator: ";
        for(int i = 0; i < 8; i++) cout << C[i] << " ";
    
        return 0;
    }

    5. Interclasare Fără Duplicate

    #include <iostream>
    using namespace std;
    
    int main() {
        int A[] = {1, 3, 5, 7};
        int B[] = {2, 3, 4, 6};
        int nA = 4, nB = 4;
    
        int C[8];
        int i = 0, j = 0, k = 0;
    
        while(i < nA && j < nB) {
            if(A[i] < B[j]) {
                C[k] = A[i];
                i++;
                k++;
            } 
            else if(A[i] > B[j]) {
                C[k] = B[j];
                j++;
                k++;
            }
            else {  // Elemente egale (duplicate)
                C[k] = A[i];  // Pune o singură dată
                i++;
                j++;
                k++;
            }
        }
    
        // Copiere resturi (dar acum dimensiunea lui C poate fi mai mică)
        while(i < nA) {
            C[k] = A[i];
            i++;
            k++;
        }
    
        while(j < nB) {
            C[k] = B[j];
            j++;
            k++;
        }
    
        cout << "Fara duplicate: ";
        for(int i = 0; i < k; i++) cout << C[i] << " ";
    
        return 0;
    }

    6. Aplicații Practice

    Aplicația 1: Unirea a doi vectori de numere pare și impare

    #include <iostream>
    using namespace std;
    
    int main() {
        int pare[] = {2, 4, 6, 8};      // SORTAT
        int impare[] = {1, 3, 5, 7};    // SORTAT
        int nPare = 4, nImpare = 4;
    
        int rezultat[8];
        int i = 0, j = 0, k = 0;
    
        while(i < nPare && j < nImpare) {
            if(pare[i] < impare[j]) {
                rezultat[k] = pare[i];
                i++;
            } else {
                rezultat[k] = impare[j];
                j++;
            }
            k++;
        }
    
        // Copiere resturi...
    
        cout << "Pare + impare: ";
        for(int i = 0; i < 8; i++) cout << rezultat[i] << " ";
    
        return 0;
    }

    Aplicația 2: Interclasare cu citire de la tastatură

    #include <iostream>
    using namespace std;
    
    int main() {
        int A[5], B[5];
    
        cout << "Introdu 5 numere SORTATE pentru A:\n";
        for(int i = 0; i < 5; i++) {
            cout << "A[" << i << "] = ";
            cin >> A[i];
        }
    
        cout << "\nIntrodu 5 numere SORTATE pentru B:\n";
        for(int i = 0; i < 5; i++) {
            cout << "B[" << i << "] = ";
            cin >> B[i];
        }
    
        int C[10];
        int i = 0, j = 0, k = 0;
    
        while(i < 5 && j < 5) {
            if(A[i] < B[j]) {
                C[k] = A[i];
                i++;
            } else {
                C[k] = B[j];
                j++;
            }
            k++;
        }
    
        while(i < 5) {
            C[k] = A[i];
            i++;
            k++;
        }
    
        while(j < 5) {
            C[k] = B[j];
            j++;
            k++;
        }
    
        cout << "\nRezultat interclasat: ";
        for(int i = 0; i < 10; i++) cout << C[i] << " ";
    
        return 0;
    }

    7. Interclasarea ca Funcție

    #include <iostream>
    using namespace std;
    
    void interclasare(int A[], int nA, int B[], int nB, int C[]) {
        int i = 0, j = 0, k = 0;
    
        while(i < nA && j < nB) {
            if(A[i] < B[j]) {
                C[k] = A[i];
                i++;
            } else {
                C[k] = B[j];
                j++;
            }
            k++;
        }
    
        while(i < nA) {
            C[k] = A[i];
            i++;
            k++;
        }
    
        while(j < nB) {
            C[k] = B[j];
            j++;
            k++;
        }
    }
    
    int main() {
        int A[] = {1, 4, 7, 9};
        int B[] = {2, 3, 5, 8};
        int C[8];
    
        interclasare(A, 4, B, 4, C);
    
        cout << "Rezultat: ";
        for(int i = 0; i < 8; i++) cout << C[i] << " ";
    
        return 0;
    }

    8. Complexitatea Algoritmului

    #include <iostream>
    using namespace std;
    
    int main() {
        cout << "=== COMPLEXITATE INTERCLASARE ===\n\n";
    
        cout << "Dacă A are n elemente și B are m elemente:\n";
        cout << "• Parcurgem fiecare element o singură dată\n";
        cout << "• Facem n + m comparații\n";
        cout << "• Complexitate: O(n + m)\n\n";
    
        cout << "EXEMPLU:\n";
        cout << "• A are 1000 elemente\n";
        cout << "• B are 2000 elemente\n";
        cout << "• Interclasarea va face cel mult 3000 de pași\n";
        cout << "• Mult mai eficient decât sortarea de la zero!\n";
    
        return 0;
    }

    9. Merge Sort – Folosind Interclasarea

    Merge Sort = împarte vectorul în jumătăți, sortează fiecare jumătate, apoi le interclasează.

    #include <iostream>
    using namespace std;
    
    void interclasare(int v[], int stanga, int mijloc, int dreapta) {
        int n1 = mijloc - stanga + 1;
        int n2 = dreapta - mijloc;
    
        int L[n1], R[n2];
    
        // Copiere în vectori temporari
        for(int i = 0; i < n1; i++) L[i] = v[stanga + i];
        for(int j = 0; j < n2; j++) R[j] = v[mijloc + 1 + j];
    
        // Interclasare
        int i = 0, j = 0, k = stanga;
    
        while(i < n1 && j < n2) {
            if(L[i] <= R[j]) {
                v[k] = L[i];
                i++;
            } else {
                v[k] = R[j];
                j++;
            }
            k++;
        }
    
        while(i < n1) {
            v[k] = L[i];
            i++;
            k++;
        }
    
        while(j < n2) {
            v[k] = R[j];
            j++;
            k++;
        }
    }
    
    void mergeSort(int v[], int stanga, int dreapta) {
        if(stanga < dreapta) {
            int mijloc = stanga + (dreapta - stanga) / 2;
    
            // Sortează cele două jumătăți
            mergeSort(v, stanga, mijloc);
            mergeSort(v, mijloc + 1, dreapta);
    
            // Interclasează jumătățile sortate
            interclasare(v, stanga, mijloc, dreapta);
        }
    }
    
    int main() {
        int v[] = {5, 2, 8, 1, 3, 7, 4, 6};
        int n = 8;
    
        mergeSort(v, 0, n-1);
    
        cout << "Sortat cu Merge Sort: ";
        for(int i = 0; i < n; i++) cout << v[i] << " ";
    
        return 0;
    }

    10. Exerciții Practice

    Exercițiul 1: Completează algoritmul

    int A[] = {1, 4, 6};
    int B[] = {2, 3, 5};
    int C[6];
    int i = 0, j = 0, k = 0;
    
    while(i < 3 && j < 3) {
        if(A[i] < B[j]) {
            C[k] = A[i];
            /* completează */
        } else {
            C[k] = B[j];
            /* completează */
        }
        k++;
    }

    Soluție:

    C[k] = A[i];
    i++;
    
    C[k] = B[j];
    j++;

    Exercițiul 2: Ce face acest cod?

    int i = 0, j = 0, k = 0;
    while(i < nA && j < nB) {
        if(A[i] <= B[j]) {
            C[k++] = A[i++];
        } else {
            C[k++] = B[j++];
        }
    }

    Răspuns: Este algoritmul de interclasare (versiune compactă).

    Exercițiul 3: Interclasare cu verificare dacă vectorii sunt sortați

    #include <iostream>
    using namespace std;
    
    bool esteSortat(int v[], int n) {
        for(int i = 0; i < n-1; i++) {
            if(v[i] > v[i+1]) return false;
        }
        return true;
    }
    
    int main() {
        int A[] = {5, 3, 1};  // NU e sortat!
        int B[] = {2, 4, 6};
    
        if(!esteSortat(A, 3) || !esteSortat(B, 3)) {
            cout << "EROARE: Vectorii trebuie sa fie sortati!" << endl;
            return 1;
        }
    
        // Continuă cu interclasarea...
    
        return 0;
    }

    Schema Universală de Interclasare:

    1. i = 0 (index pentru A), j = 0 (index pentru B), k = 0 (index pentru C)
    2. Cât timp i < nA și j < nB:
       - Dacă A[i] < B[j]: C[k] = A[i], i++
       - Altfel: C[k] = B[j], j++
       - k++
    3. Copiază restul din A (dacă există)
    4. Copiază restul din B (dacă există)

    În concluzie:

    • Interclasarea funcționează DOAR pe vectori SORTAȚI
    • Complexitatea e O(n + m) – extrem de eficientă
    • Merge Sort se bazează pe interclasare
    • Regula de aur: Compară, alege, avansează în vectorul ales

    Când folosești interclasarea?

    1. Când ai două liste sortate și vrei să le unesti păstrând ordinea
    2. În Merge Sort pentru a combina jumătățile sortate
    3. În baze de date pentru a uni rezultate sortate
    4. În sisteme de fișiere pentru a interclasa fișiere sortate
  • Metode de Ordonare: Arta de a Aranja În Ordine

    Bun, hai să vorbim despre unul dintre cele mai importante și fundamentale subiecte din algoritmică: METODELE DE ORDONARE (SORTARE). Nu e doar despre aranjare (cuvânt plictisitor) și organizare. E despre cum transformi o grămadă dezordonată de date într-o listă perfect organizată, ca să poți căută rapid, analiza ușor și înțelege mai bine informațiile.

    1. De ce Să Sortăm? “Căutarea Într-o Agendă”

    Gândește-te la sortare ca la aranjarea unei agende telefonice în ordine alfabetică:

    • Fără sortare: Cauți “Popescu” → verifici toate numele una câte una
    • Cu sortare: Cauți “Popescu” → mergi direct la litera P

    4 motive principale pentru sortare:

    1. Căutare rapidă – poți folosi căutarea binară
    2. Date mai lizibile – vezi imediat min, max, mediană
    3. Pregătește pentru alte operații – unirea a doi vectori sortați e ușoară
    4. E necesară pentru multe algoritme – statistici, grafice, baze de date

    2. Bubble Sort (Sortarea Bulelor): “Cel Mai Simplu”

    Cum funcționează: Compară două elemente vecine, le schimbă dacă sunt în ordine greșită, repetă până când tot vectorul e sortat. Ca bulele care urcă în suprafața apei.

    #include <iostream>
    using namespace std;
    
    int main() {
        int v[] = {5, 2, 8, 1, 3};
        int n = 5;
    
        cout << "Vector nesortat: ";
        for(int i = 0; i < n; i++) cout << v[i] << " ";
        cout << endl;
    
        // Bubble Sort
        for(int i = 0; i < n-1; i++) {
            for(int j = 0; j < n-i-1; j++) {
                if(v[j] > v[j+1]) {
                    // Schimbă elementele
                    int temp = v[j];
                    v[j] = v[j+1];
                    v[j+1] = temp;
                }
            }
        }
    
        cout << "Vector sortat (Bubble Sort): ";
        for(int i = 0; i < n; i++) cout << v[i] << " ";
    
        return 0;
    }

    Ce se întâmplă pas cu pas:

    5 2 8 1 3  → 2 5 1 3 8  → 2 1 3 5 8  → 1 2 3 5 8

    Optimizare: Dacă într-o trecere nu se face niciun schimb, vectorul e deja sortat.

    Complexitate: O(n²) în cel mai rău caz

    Când să folosești: Pentru vectori mici sau aproape sortați

    3. Selection Sort (Sortarea prin Selecție): “Găsește Minimul”

    Cum funcționează: Găsește cel mai mic element, îl pune pe prima poziție. Apoi găsește următorul cel mai mic din rest, îl pune pe a doua poziție, etc.

    #include <iostream>
    using namespace std;
    
    int main() {
        int v[] = {5, 2, 8, 1, 3};
        int n = 5;
    
        cout << "Vector nesortat: ";
        for(int i = 0; i < n; i++) cout << v[i] << " ";
        cout << endl;
    
        // Selection Sort
        for(int i = 0; i < n-1; i++) {
            // Găsește poziția minimului în partea nesortată
            int pozitieMin = i;
    
            for(int j = i+1; j < n; j++) {
                if(v[j] < v[pozitieMin]) {
                    pozitieMin = j;
                }
            }
    
            // Schimbă elementul minim cu primul din partea nesortată
            if(pozitieMin != i) {
                int temp = v[i];
                v[i] = v[pozitieMin];
                v[pozitieMin] = temp;
            }
        }
    
        cout << "Vector sortat (Selection Sort): ";
        for(int i = 0; i < n; i++) cout << v[i] << " ";
    
        return 0;
    }

    Ce se întâmplă pas cu pas:

    5 2 8 1 3  → 1 2 8 5 3  → 1 2 8 5 3  → 1 2 3 5 8  → 1 2 3 5 8

    Complexitate: O(n²) întotdeauna (face aceeași număr de comparări indiferent dacă e sortat sau nu)

    Când să folosești: Când vrei putine schimbări (face doar n-1 schimbări)

    4. Insertion Sort (Sortarea prin Inserție): “Ca Să Înșurubezi”

    Cum funcționează: Luați un element, inserați-l în poziția corectă în partea deja sortată. Ca și cum ai sorta cărți de joc în mână.

    #include <iostream>
    using namespace std;
    
    int main() {
        int v[] = {5, 2, 8, 1, 3};
        int n = 5;
    
        cout << "Vector nesortat: ";
        for(int i = 0; i < n; i++) cout << v[i] << " ";
        cout << endl;
    
        // Insertion Sort
        for(int i = 1; i < n; i++) {
            int elementCurent = v[i];
            int j = i - 1;
    
            // Mută elementele mai mari decât elementCurent cu o poziție la dreapta
            while(j >= 0 && v[j] > elementCurent) {
                v[j+1] = v[j];
                j--;
            }
    
            // Inserează elementCurent în poziția corectă
            v[j+1] = elementCurent;
        }
    
        cout << "Vector sortat (Insertion Sort): ";
        for(int i = 0; i < n; i++) cout << v[i] << " ";
    
        return 0;
    }

    Ce se întâmplă pas cu pas:

    5|2 8 1 3  → 2 5|8 1 3  → 2 5 8|1 3  → 1 2 5 8|3  → 1 2 3 5 8

    Complexitate: O(n²) în cel mai rău caz, O(n) dacă vectorul e aproape sortat

    Când să folosești: Pentru vectori mici sau aproape sortați

    5. Counting Sort (Sortarea prin Numărare): “Cel Mai Rapid” pentru numere mici

    Cum funcționează: Numără de câte ori apare fiecare valoare, apoi reconstruiește vectorul sortat.

    #include <iostream>
    using namespace std;
    
    int main() {
        int v[] = {4, 2, 2, 8, 3, 3, 1};
        int n = 7;
    
        cout << "Vector nesortat: ";
        for(int i = 0; i < n; i++) cout << v[i] << " ";
        cout << endl;
    
        // Găsește valoarea maximă
        int max = v[0];
        for(int i = 1; i < n; i++) {
            if(v[i] > max) max = v[i];
        }
    
        // Vector de frecvență
        int frecventa[max+1] = {0};
    
        // Numără fiecare element
        for(int i = 0; i < n; i++) {
            frecventa[v[i]]++;
        }
    
        // Reconstruiește vectorul sortat
        int index = 0;
        for(int i = 0; i <= max; i++) {
            while(frecventa[i] > 0) {
                v[index] = i;
                index++;
                frecventa[i]--;
            }
        }
    
        cout << "Vector sortat (Counting Sort): ";
        for(int i = 0; i < n; i++) cout << v[i] << " ";
    
        return 0;
    }

    Ce se întâmplă:

    Numără: 1 apare 1 dată, 2 apare de 2 ori, 3 apare de 2 ori, 4 apare 1 dată, 8 apare 1 dată
    Reconstruiește: 1 2 2 3 3 4 8

    Complexitate: O(n + k) unde k este valoarea maximă

    Când să folosești: Când ai numere întregi într-un interval mic

    6. Compararea Metodelor

    #include <iostream>
    using namespace std;
    
    int main() {
        cout << "=== COMPARATIE METODE DE SORTARE ===\n\n";
    
        cout << "BUBBLE SORT:\n";
        cout << "- Complexitate: O(n²) in cel mai rau caz\n";
        cout << "- Când: vectori mici sau aproape sortati\n";
        cout << "- Avantaje: simplu de inteles\n";
        cout << "- Dezavantaje: foarte lent pentru vectori mari\n\n";
    
        cout << "SELECTION SORT:\n";
        cout << "- Complexitate: O(n²) intotdeauna\n";
        cout << "- Când: cand vrei putine schimbari\n";
        cout << "- Avantaje: face doar n-1 schimburi\n";
        cout << "- Dezavantaje: tot O(n²) comparatii\n\n";
    
        cout << "INSERTION SORT:\n";
        cout << "- Complexitate: O(n²) in cel mai rau caz, O(n) daca e aproape sortat\n";
        cout << "- Când: vectori mici sau aproape sortati\n";
        cout << "- Avantaje: bun pentru date care vin in flux\n";
        cout << "- Dezavantaje: lent pentru vectori invers sortati\n\n";
    
        cout << "COUNTING SORT:\n";
        cout << "- Complexitate: O(n + k) unde k e valoarea maxima\n";
        cout << "- Când: numere intregi intr-un interval mic\n";
        cout << "- Avantaje: cel mai rapid in conditii ideale\n";
        cout << "- Dezavantaje: foloseste memorie extra\n";
    
        return 0;
    }

    7. Sortare Descrescătoare: “Doar Schimbi Semnul”

    Pentru orice algoritm, schimbă > cu < pentru a sorta descrescător!

    #include <iostream>
    using namespace std;
    
    int main() {
        int v[] = {5, 2, 8, 1, 3};
        int n = 5;
    
        // Bubble Sort descrescator
        for(int i = 0; i < n-1; i++) {
            for(int j = 0; j < n-i-1; j++) {
                if(v[j] < v[j+1]) {  // < in loc de >
                    int temp = v[j];
                    v[j] = v[j+1];
                    v[j+1] = temp;
                }
            }
        }
    
        cout << "Sortat descrescator: ";
        for(int i = 0; i < n; i++) cout << v[i] << " ";
    
        return 0;
    }

    8. Implementare cu Funcții

    #include <iostream>
    using namespace std;
    
    // Bubble Sort
    void bubbleSort(int v[], int n) {
        for(int i = 0; i < n-1; i++) {
            for(int j = 0; j < n-i-1; j++) {
                if(v[j] > v[j+1]) {
                    int temp = v[j];
                    v[j] = v[j+1];
                    v[j+1] = temp;
                }
            }
        }
    }
    
    // Selection Sort
    void selectionSort(int v[], int n) {
        for(int i = 0; i < n-1; i++) {
            int minIdx = i;
            for(int j = i+1; j < n; j++) {
                if(v[j] < v[minIdx]) minIdx = j;
            }
            if(minIdx != i) {
                int temp = v[i];
                v[i] = v[minIdx];
                v[minIdx] = temp;
            }
        }
    }
    
    // Insertion Sort
    void insertionSort(int v[], int n) {
        for(int i = 1; i < n; i++) {
            int key = v[i];
            int j = i-1;
            while(j >= 0 && v[j] > key) {
                v[j+1] = v[j];
                j--;
            }
            v[j+1] = key;
        }
    }
    
    int main() {
        int v[] = {5, 2, 8, 1, 3};
        int n = 5;
    
        // Alege algoritmul
        bubbleSort(v, n);  // Schimbă cu selectionSort sau insertionSort
    
        cout << "Sortat: ";
        for(int i = 0; i < n; i++) cout << v[i] << " ";
    
        return 0;
    }

    9. Testarea Corectitudinii

    #include <iostream>
    using namespace std;
    
    bool esteSortat(int v[], int n) {
        for(int i = 0; i < n-1; i++) {
            if(v[i] > v[i+1]) {
                return false;  // Vectorul nu e sortat
            }
        }
        return true;  // Vectorul e sortat
    }
    
    int main() {
        int v[] = {1, 2, 3, 4, 5};
        int n = 5;
    
        if(esteSortat(v, n)) {
            cout << "Vectorul este sortat corect!" << endl;
        } else {
            cout << "Vectorul NU este sortat corect!" << endl;
        }
    
        return 0;
    }

    10. Exerciții Practice

    Exercițiul 1: Completează Bubble Sort

    int v[] = {4, 1, 3, 2};
    int n = 4;
    
    for(int i = 0; i < n-1; i++) {
        for(int j = 0; j < n-i-1; j++) {
            if(/* condiție */) {
                int temp = v[j];
                v[j] = v[j+1];
                v[j+1] = /* ce pui aici? */;
            }
        }
    }

    Soluție:

    if(v[j] > v[j+1]) {
        // ...
        v[j+1] = temp;
    }

    Exercițiul 2: Ce face acest cod?

    for(int i = 0; i < n-1; i++) {
        int minIdx = i;
        for(int j = i+1; j < n; j++) {
            if(v[j] < v[minIdx]) minIdx = j;
        }
        int temp = v[i];
        v[i] = v[minIdx];
        v[minIdx] = temp;
    }

    Răspuns: Este algoritmul Selection Sort.

    Exercițiul 3: Sortează doar numerele pare

    #include <iostream>
    using namespace std;
    
    int main() {
        int v[] = {5, 2, 8, 1, 6, 3};
        int n = 6;
    
        // Bubble Sort doar pentru elementele pare
        for(int i = 0; i < n-1; i++) {
            for(int j = 0; j < n-i-1; j++) {
                // Sortează doar dacă ambele sunt pare
                if(v[j] % 2 == 0 && v[j+1] % 2 == 0 && v[j] > v[j+1]) {
                    int temp = v[j];
                    v[j] = v[j+1];
                    v[j+1] = temp;
                }
            }
        }
    
        cout << "Numerele pare sortate: ";
        for(int i = 0; i < n; i++) {
            if(v[i] % 2 == 0) cout << v[i] << " ";
        }
    
        return 0;
    }

    În concluzie:

    • Bubble Sort = cel mai simplu (compară vecinii)
    • Selection Sort = găsește minimul și îl pune la început
    • Insertion Sort = inserează fiecare element în poziția corectă
    • Counting Sort = cel mai rapid pentru numere într-un interval mic

    Regula de aur: Alege algoritmul în funcție de datele tale:

    • Vector mic sau aproape sortat → Bubble, Selection, Insertion
    • Numere întregi într-un interval mic → Counting Sort
    • Vector mare → algoritmi mai avansați (Quick Sort, Merge Sort)
  • Determinare Minim/Maxim: Găsirea “Campionilor” dintr-o Multime

    Bun, hai să vorbim despre unul dintre cele mai fundamentale și utile algoritme din programare: GĂSIREA MINIMULUI ȘI MAXIMULUI. Nu e doar despre comparare (cuvânt simplu) și selecție. E despre cum identifici rapid cel mai mic și cel mai mare element dintr-o colecție, fie că e vorba de note, temperaturi, prețuri sau orice altceva.

    1. Ce înseamnă “Minim” și “Maxim”? “Extremele” Mulțimii

    Definiție:

    • Minim = cel mai mic număr dintr-o mulțime
    • Maxim = cel mai mare număr dintr-o mulțime

    Analogie cu un Concurs:

    Ai 10 sportivi care au sărit în lungime:

    • Minim = cel mai scăzut salt (cel mai puțin bun)
    • Maxim = cel mai lung salt (câștigătorul)

    Exemplu simplu:

    Numere: 5, 2, 8, 1, 9, 3
    Minim = 1 (cel mai mic)
    Maxim = 9 (cel mai mare)

    2. Algoritmul de Bază pentru Minim

    Strategie: Presupun că primul element este minimul, apoi verific pe rând toate celelalte.

    #include <iostream>
    using namespace std;
    
    int main() {
        int numere[] = {5, 2, 8, 1, 9, 3};
        int n = 6;  // Numărul de elemente
    
        // Presupun că primul element este minimul
        int minim = numere[0];
    
        // Verific pe rând toate elementele
        for(int i = 1; i < n; i++) {
            if(numere[i] < minim) {  // Dacă am găsit un număr mai mic
                minim = numere[i];    // Acesta devine noul minim
            }
        }
    
        cout << "Minimul este: " << minim << endl;
        return 0;
    }

    Cum funcționează pas cu pas:

    Start: minim = 5 (primul element)
    
    Pasul 1: Compar 2 < 5? DA → minim = 2
    Pasul 2: Compar 8 < 2? NU → minim rămâne 2  
    Pasul 3: Compar 1 < 2? DA → minim = 1
    Pasul 4: Compar 9 < 1? NU → minim rămâne 1
    Pasul 5: Compar 3 < 1? NU → minim rămâne 1
    
    Rezultat: minim = 1

    3. Algoritmul de Bază pentru Maxim

    Aceeași logică, dar inversă!

    #include <iostream>
    using namespace std;
    
    int main() {
        int numere[] = {5, 2, 8, 1, 9, 3};
        int n = 6;
    
        // Presupun că primul element este maximul
        int maxim = numere[0];
    
        // Verific pe rând toate elementele
        for(int i = 1; i < n; i++) {
            if(numere[i] > maxim) {  // Dacă am găsit un număr mai mare
                maxim = numere[i];    // Acesta devine noul maxim
            }
        }
    
        cout << "Maximul este: " << maxim << endl;
        return 0;
    }

    4. Găsirea atât a Minimului cât și a Maximului (într-o singură parcurgere)

    #include <iostream>
    using namespace std;
    
    int main() {
        int numere[] = {5, 2, 8, 1, 9, 3};
        int n = 6;
    
        // Inițializez ambele cu primul element
        int minim = numere[0];
        int maxim = numere[0];
    
        // O singură parcurgere pentru ambele
        for(int i = 1; i < n; i++) {
            if(numere[i] < minim) {
                minim = numere[i];  // Actualizez minimul
            }
    
            if(numere[i] > maxim) {
                maxim = numere[i];  // Actualizez maximul
            }
        }
    
        cout << "Minim: " << minim << endl;
        cout << "Maxim: " << maxim << endl;
    
        return 0;
    }

    5. Variante și Optimizări

    5.1 Cu poziția unde se află minimul/maximul

    #include <iostream>
    using namespace std;
    
    int main() {
        int numere[] = {5, 2, 8, 1, 9, 3};
        int n = 6;
    
        int minim = numere[0];
        int pozitieMinim = 0;  // Și rețin unde l-am găsit
    
        for(int i = 1; i < n; i++) {
            if(numere[i] < minim) {
                minim = numere[i];
                pozitieMinim = i;  // Salvez poziția
            }
        }
    
        cout << "Minimul " << minim << " se afla pe pozitia " 
             << pozitieMinim << endl;
    
        return 0;
    }

    5.2 Pentru numere reale

    #include <iostream>
    using namespace std;
    
    int main() {
        double temperaturi[] = {22.5, 18.3, 25.1, 19.8, 23.4};
        int n = 5;
    
        double minim = temperaturi[0];
        double maxim = temperaturi[0];
    
        for(int i = 1; i < n; i++) {
            if(temperaturi[i] < minim) minim = temperaturi[i];
            if(temperaturi[i] > maxim) maxim = temperaturi[i];
        }
    
        cout << "Temperatura minima: " << minim << "°C" << endl;
        cout << "Temperatura maxima: " << maxim << "°C" << endl;
    
        return 0;
    }

    5.3 Citire de la tastatură

    #include <iostream>
    using namespace std;
    
    int main() {
        int n;
        cout << "Cate numere? ";
        cin >> n;
    
        if(n <= 0) {
            cout << "Trebuie cel putin un numar!" << endl;
            return 1;
        }
    
        int primulNumar;
        cout << "Numarul 1: ";
        cin >> primulNumar;
    
        int minim = primulNumar;
        int maxim = primulNumar;
    
        // Deja am citit primul, deci încep de la 2
        for(int i = 2; i <= n; i++) {
            int numar;
            cout << "Numarul " << i << ": ";
            cin >> numar;
    
            if(numar < minim) minim = numar;
            if(numar > maxim) maxim = numar;
        }
    
        cout << "\nMinim: " << minim << endl;
        cout << "Maxim: " << maxim << endl;
    
        return 0;
    }

    6. Aplicații Practice

    Aplicația 1: Cel mai bun și cel mai slab elev

    #include <iostream>
    using namespace std;
    
    int main() {
        int note[] = {9, 7, 10, 5, 8, 6};
        int n = 6;
    
        int notaMaxima = note[0];
        int notaMinima = note[0];
    
        for(int i = 1; i < n; i++) {
            if(note[i] > notaMaxima) notaMaxima = note[i];
            if(note[i] < notaMinima) notaMinima = note[i];
        }
    
        cout << "Cea mai buna nota: " << notaMaxima << endl;
        cout << "Cea mai slaba nota: " << notaMinima << endl;
    
        return 0;
    }

    Aplicația 2: Temperaturi extreme

    #include <iostream>
    using namespace std;
    
    int main() {
        double temp[] = {-5.2, 3.1, 0.5, -2.8, 4.3, -1.7};
        int n = 6;
    
        double ceaMaiRece = temp[0];
        double ceaMaiCaldă = temp[0];
    
        for(int i = 1; i < n; i++) {
            if(temp[i] < ceaMaiRece) ceaMaiRece = temp[i];
            if(temp[i] > ceaMaiCaldă) ceaMaiCaldă = temp[i];
        }
    
        cout << "Cea mai rece temperatura: " << ceaMaiRece << "°C" << endl;
        cout << "Cea mai calda temperatura: " << ceaMaiCaldă << "°C" << endl;
    
        return 0;
    }

    Aplicația 3: Preturi minime și maxime

    #include <iostream>
    using namespace std;
    
    int main() {
        double preturi[] = {29.99, 45.50, 15.75, 89.99, 32.25};
        int n = 5;
    
        double celMaiIeftin = preturi[0];
        double celMaiScump = preturi[0];
    
        for(int i = 1; i < n; i++) {
            if(preturi[i] < celMaiIeftin) celMaiIeftin = preturi[i];
            if(preturi[i] > celMaiScump) celMaiScump = preturi[i];
        }
    
        cout << "Cel mai ieftin: " << celMaiIeftin << " RON" << endl;
        cout << "Cel mai scump: " << celMaiScump << " RON" << endl;
    
        return 0;
    }

    7. Cazuri Speciale

    7.1 Vector gol sau cu un singur element

    #include <iostream>
    using namespace std;
    
    int main() {
        int numere[] = {42};  // Doar un element
        int n = 1;
    
        if(n == 0) {
            cout << "Vector gol!" << endl;
            return 1;
        }
    
        // Pentru un singur element, el e și minim și maxim
        int minim = numere[0];
        int maxim = numere[0];
    
        cout << "Minim = Maxim = " << minim << endl;
    
        return 0;
    }

    7.2 Toate numerele egale

    #include <iostream>
    using namespace std;
    
    int main() {
        int numere[] = {7, 7, 7, 7, 7};
        int n = 5;
    
        int minim = numere[0];
        int maxim = numere[0];
    
        for(int i = 1; i < n; i++) {
            if(numere[i] < minim) minim = numere[i];
            if(numere[i] > maxim) maxim = numere[i];
        }
    
        cout << "Minim: " << minim << endl;
        cout << "Maxim: " << maxim << endl;
        cout << "Sunt " << (minim == maxim ? "toate egale" : "diferite") << endl;
    
        return 0;
    }

    7.3 Numere negative

    #include <iostream>
    using namespace std;
    
    int main() {
        int numere[] = {-5, -2, -8, -1, -9};
        int n = 5;
    
        int minim = numere[0];
        int maxim = numere[0];
    
        for(int i = 1; i < n; i++) {
            if(numere[i] < minim) minim = numere[i];
            if(numere[i] > maxim) maxim = numere[i];
        }
    
        cout << "Minim (cel mai mic): " << minim << endl;
        cout << "Maxim (cel mai mare): " << maxim << endl;
    
        return 0;
    }

    8. Algoritmi Avansați (Conceptual)

    8.1 Găsirea celui de-al doilea minim/maxim

    #include <iostream>
    using namespace std;
    
    int main() {
        int numere[] = {5, 2, 8, 1, 9, 3};
        int n = 6;
    
        // Găsesc minimul și maximul
        int minim = numere[0], maxim = numere[0];
    
        for(int i = 1; i < n; i++) {
            if(numere[i] < minim) minim = numere[i];
            if(numere[i] > maxim) maxim = numere[i];
        }
    
        // Găsesc al doilea minim (primul mai mare decât minim)
        int alDoileaMinim = maxim;  // Pornesc de la maxim
    
        for(int i = 0; i < n; i++) {
            if(numere[i] > minim && numere[i] < alDoileaMinim) {
                alDoileaMinim = numere[i];
            }
        }
    
        cout << "Minim: " << minim << endl;
        cout << "Al doilea minim: " << alDoileaMinim << endl;
    
        return 0;
    }

    8.2 Minimul și Maximul într-o matrice

    #include <iostream>
    using namespace std;
    
    int main() {
        int matrice[3][3] = {
            {5, 2, 8},
            {1, 9, 3},
            {4, 7, 6}
        };
    
        int minim = matrice[0][0];
        int maxim = matrice[0][0];
    
        // Parcurg toată matricea
        for(int i = 0; i < 3; i++) {
            for(int j = 0; j < 3; j++) {
                if(matrice[i][j] < minim) minim = matrice[i][j];
                if(matrice[i][j] > maxim) maxim = matrice[i][j];
            }
        }
    
        cout << "Minim in matrice: " << minim << endl;
        cout << "Maxim in matrice: " << maxim << endl;
    
        return 0;
    }

    9. Exerciții Practice

    Exercițiul 1: Completează algoritmul

    int numere[] = {7, 3, 9, 1, 5};
    int n = 5;
    int minim = numere[0];
    
    for(int i = 1; i < n; i++) {
        if(/* condiție */) {
            minim = /* ce pui aici? */;
        }
    }
    
    cout << "Minim: " << minim;

    Soluție:

    if(numere[i] < minim) {
        minim = numere[i];
    }

    Exercițiul 2: Ce face acest cod?

    int vector[] = {4, 2, 7, 1, 9};
    int max = vector[0];
    
    for(int i = 1; i < 5; i++) {
        if(vector[i] > max) {
            max = vector[i];
        }
    }

    Răspuns: Găsește maximul din vector.

    Exercițiul 3: Găsește minimul dintr-un șir citit

    #include <iostream>
    using namespace std;
    
    int main() {
        int n;
        cout << "Cate numere? ";
        cin >> n;
    
        if(n <= 0) return 1;
    
        int primul;
        cin >> primul;
    
        int minim = primul;
    
        for(int i = 2; i <= n; i++) {
            int x;
            cin >> x;
            if(x < minim) minim = x;
        }
    
        cout << "Minim: " << minim << endl;
        return 0;
    }

    10. Schema Universală pentru Minim/Maxim

    Pentru MINIM:

    minim = primul_element;
    
    for(fiecare_element element) {
        if(element < minim) {
            minim = element;
        }
    }

    Pentru MAXIM:

    maxim = primul_element;
    
    for(fiecare_element element) {
        if(element > maxim) {
            maxim = element;
        }
    }

    În concluzie:

    • Minimul se găsește cu <
    • Maximul se găsește cu >
    • Mereu pornești de la primul element
    • Parcurgi o singură dată toate elementele

    Regula de aur: Orice algoritm de minim/maxim are complexitatea O(n) – parcurge vectorul o singură dată. Nu există algoritm mai rapid pentru a găsi minimul/maximul într-o mulțime nesortată!

  • Șirul lui Fibonacci și Sume cu Termen General Dat

    Bun, hai să vorbim despre unul dintre cele mai fascinante și utile șiruri din matematică și programare: ȘIRUL LUI FIBONACCI. Nu e doar despre numere (cuvânt rece) și secvențe. E despre o relație de recurență care apare peste tot în natură: la cochilii de melc, la așezarea frunzelor, la proporțiile corpului uman. Și apoi vom vorbi despre cum calculăm sume atunci când știm formula termenului general.

    1. Ce este Șirul lui Fibonacci? “Suma Celor Doi Anteriori”

    Definiție: Fiecare termen este suma celor doi termeni anteriori.

    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, …

    Analogie cu Iepuri:

    Luna 1: 1 pereche de iepuri (tineri)
    Luna 2: încă 1 pereche (tineri devin adulți)
    Luna 3: 2 perechi (adulții fac pui)
    Luna 4: 3 perechi (și așa mai departe)

    2. Calcul Fibonacci – Metoda Iterativă (cea mai bună!)

    #include <iostream>
    using namespace std;
    
    int main() {
        int n = 10;  // Al câtelea termen vrem
    
        if(n == 0) {
            cout << "F(0) = 0" << endl;
            return 0;
        }
        if(n == 1) {
            cout << "F(1) = 1" << endl;
            return 0;
        }
    
        int a = 0;  // F(n-2)
        int b = 1;  // F(n-1)
        int c;      // F(n)
    
        cout << "F(0) = 0" << endl;
        cout << "F(1) = 1" << endl;
    
        for(int i = 2; i <= n; i++) {
            c = a + b;      // Termenul curent
            cout << "F(" << i << ") = " << c << endl;
    
            // Pregătim următorul pas
            a = b;
            b = c;
        }
    
        return 0;
    }

    3. Calcul Fibonacci – Metoda Recursivă (simplă dar ineficientă)

    #include <iostream>
    using namespace std;
    
    int fibonacci(int n) {
        if(n == 0) return 0;
        if(n == 1) return 1;
    
        return fibonacci(n-1) + fibonacci(n-2);
    }
    
    int main() {
        int n = 10;
        cout << "F(" << n << ") = " << fibonacci(n) << endl;
        return 0;
    }

    Problemă cu recursivitatea: Calculează aceleași valori de multe ori!
    Pentru F(5) calculează:

    • F(5) = F(4) + F(3)
    • F(4) = F(3) + F(2)
    • F(3) = F(2) + F(1)
    • F(2) = F(1) + F(0)

    4. Fibonacci cu Memoizare (optimizat)

    #include <iostream>
    using namespace std;
    
    int fib[100];  // Memorie pentru rezultate calculate
    
    int fibonacciMemo(int n) {
        if(n == 0) return 0;
        if(n == 1) return 1;
    
        if(fib[n] != 0) {  // Dacă l-am calculat deja
            return fib[n];
        }
    
        fib[n] = fibonacciMemo(n-1) + fibonacciMemo(n-2);
        return fib[n];
    }
    
    int main() {
        // Inițializează memoria cu 0
        for(int i = 0; i < 100; i++) {
            fib[i] = 0;
        }
    
        int n = 10;
        cout << "F(" << n << ") = " << fibonacciMemo(n) << endl;
        return 0;
    }

    5. Proprietăți interesante ale șirului Fibonacci

    5.1 Suma primilor n termeni

    #include <iostream>
    using namespace std;
    
    int main() {
        int n = 10;
        int suma = 0;
    
        int a = 0, b = 1;
    
        if(n >= 1) suma += a;  // F(0)
        if(n >= 2) suma += b;  // F(1)
    
        for(int i = 2; i <= n; i++) {
            int c = a + b;
            suma += c;
            a = b;
            b = c;
        }
    
        cout << "Suma primilor " << n+1 << " termeni Fibonacci: " << suma << endl;
        cout << "Formula: F(n+2) - 1 = " << (b - 1) << endl;  // b = F(n+1)
    
        return 0;
    }

    5.2 Numerele Fibonacci pare

    #include <iostream>
    using namespace std;
    
    int main() {
        cout << "Numerele Fibonacci pare pana la 100:\n";
    
        int a = 0, b = 1;
    
        while(a <= 100) {
            if(a % 2 == 0) {
                cout << a << " ";
            }
    
            int c = a + b;
            a = b;
            b = c;
        }
    
        return 0;
    }

    6. Sume cu Termen General Dat

    Când avem o formulă pentru termenul general, putem calcula sume eficient.

    Exemplu 1: Suma pătratelor primelor n numere
    Termen general: aₖ = k²
    Suma: S = 1² + 2² + 3² + … + n²

    #include <iostream>
    using namespace std;
    
    int main() {
        int n = 10;
        int suma = 0;
    
        // Metoda 1: Adună direct
        for(int k = 1; k <= n; k++) {
            suma += k * k;
        }
        cout << "Suma patratelor: " << suma << endl;
    
        // Metoda 2: Folosește formula
        // S = n(n+1)(2n+1)/6
        int sumaFormula = n * (n + 1) * (2*n + 1) / 6;
        cout << "Cu formula: " << sumaFormula << endl;
    
        return 0;
    }

    Exemplu 2: Suma cuburilor
    Termen general: aₖ = k³
    Formula: S = [n(n+1)/2]²

    #include <iostream>
    using namespace std;
    
    int main() {
        int n = 10;
    
        // Cu buclă
        int sumaBucla = 0;
        for(int k = 1; k <= n; k++) {
            sumaBucla += k * k * k;
        }
    
        // Cu formula
        int sumaFormula = (n * (n + 1) / 2);
        sumaFormula = sumaFormula * sumaFormula;
    
        cout << "Suma cuburilor:\n";
        cout << "Cu bucla: " << sumaBucla << endl;
        cout << "Cu formula: " << sumaFormula << endl;
    
        return 0;
    }

    Exemplu 3: Suma puterilor lui 2
    Termen general: aₖ = 2ᵏ
    Suma: S = 2ⁿ⁺¹ – 2

    #include <iostream>
    using namespace std;
    
    int main() {
        int n = 10;
        int suma = 0;
        int putere = 1;
    
        for(int k = 1; k <= n; k++) {
            putere *= 2;  // 2ᵏ
            suma += putere;
        }
    
        cout << "Suma: " << suma << endl;
        cout << "Cu formula 2^(n+1)-2: " << ( (1 << (n+1)) - 2 ) << endl;
    
        return 0;
    }

    7. Progresii Aritmetice și Geometrice

    7.1 Progresie Aritmetică (PA)
    Termen general: aₖ = a₁ + (k-1) * r
    Suma: S = n(a₁ + aₙ)/2

    #include <iostream>
    using namespace std;
    
    int main() {
        int a1 = 3;  // Primul termen
        int r = 2;   // Rația
        int n = 10;  // Număr de termeni
    
        // Calcul cu buclă
        int suma = 0;
        int termen = a1;
    
        for(int i = 0; i < n; i++) {
            suma += termen;
            termen += r;  // Următorul termen
        }
    
        // Calcul cu formula
        int an = a1 + (n-1) * r;  // Ultimul termen
        int sumaFormula = n * (a1 + an) / 2;
    
        cout << "Suma PA: " << suma << " = " << sumaFormula << endl;
    
        return 0;
    }

    7.2 Progresie Geometrică (PG)
    Termen general: aₖ = a₁ × rᵏ⁻¹
    Suma: S = a₁(1 – rⁿ)/(1 – r) pentru r ≠ 1

    #include <iostream>
    using namespace std;
    
    int main() {
        int a1 = 2;  // Primul termen
        int r = 3;   // Rația
        int n = 5;   // Număr de termeni
    
        // Calcul cu buclă
        int suma = 0;
        int termen = a1;
    
        for(int i = 0; i < n; i++) {
            suma += termen;
            termen *= r;  // Următorul termen
        }
    
        // Calcul cu formula
        int sumaFormula;
        if(r == 1) {
            sumaFormula = n * a1;
        } else {
            // a₁(1 - rⁿ)/(1 - r)
            int rn = 1;
            for(int i = 0; i < n; i++) {
                rn *= r;
            }
            sumaFormula = a1 * (1 - rn) / (1 - r);
        }
    
        cout << "Suma PG: " << suma << " = " << sumaFormula << endl;
    
        return 0;
    }

    8. Aplicații Practice cu Fibonacci

    Aplicația 1: Verifică dacă un număr e Fibonacci

    #include <iostream>
    using namespace std;
    
    int main() {
        int numar = 34;
        bool esteFibonacci = false;
    
        int a = 0, b = 1;
    
        while(a <= numar) {
            if(a == numar) {
                esteFibonacci = true;
                break;
            }
    
            int c = a + b;
            a = b;
            b = c;
        }
    
        if(esteFibonacci) {
            cout << numar << " este numar Fibonacci!" << endl;
        } else {
            cout << numar << " NU este numar Fibonacci!" << endl;
        }
    
        return 0;
    }

    Aplicația 2: Raportul a doi termeni Fibonacci consecutivi
    Tinde către φ (phi) = (1+√5)/2 ≈ 1.618 (numărul de aur)

    #include <iostream>
    #include <iomanip>
    using namespace std;
    
    int main() {
        cout << fixed << setprecision(10);
    
        int a = 0, b = 1;
    
        cout << "Raportul F(n+1)/F(n) tinde catre phi (1.618...)\n\n";
    
        for(int i = 1; i <= 20; i++) {
            int c = a + b;
    
            if(a > 0) {  // Evită împărțirea la 0
                double raport = (double)b / a;
                cout << "F(" << i << ")/F(" << i-1 << ") = " 
                     << raport << endl;
            }
    
            a = b;
            b = c;
        }
    
        return 0;
    }

    Aplicația 3: Fibonacci pătrat – Proprietate interesantă
    F(n) × F(n+1) ≈ F(n+1)² – F(n)²

    #include <iostream>
    using namespace std;
    
    int main() {
        int n = 10;
        int a = 0, b = 1;
    
        for(int i = 0; i < n; i++) {
            int c = a + b;
    
            if(i >= 2) {
                int produs = a * b;
                int diferenta = b*b - a*a;
    
                cout << "F(" << i-1 << ")×F(" << i << ") = " << produs << endl;
                cout << "F(" << i << ")² - F(" << i-1 << ")² = " << diferenta << endl;
                cout << "Sunt " << (produs == diferenta ? "EGALE" : "DIFERITE") << "\n\n";
            }
    
            a = b;
            b = c;
        }
    
        return 0;
    }

    9. Exerciții Practice

    Exercițiul 1: Completează codul pentru Fibonacci

    int n = 8;
    int f0 = 0, f1 = 1, fn;
    
    if(n == 0) fn = f0;
    else if(n == 1) fn = f1;
    else {
        for(int i = 2; i <= n; i++) {
            fn = /* completează */;
            f0 = f1;
            f1 = /* completează */;
        }
    }
    
    cout << "F(" << n << ") = " << fn;

    Soluție:

    fn = f0 + f1;
    f1 = fn;

    Exercițiul 2: Calculează suma alternantă
    S = F(1) – F(2) + F(3) – F(4) + … ± F(n)

    #include <iostream>
    using namespace std;
    
    int main() {
        int n = 10;
        int suma = 0;
        int semn = 1;  // 1 pentru +, -1 pentru -
    
        int a = 0, b = 1;
    
        for(int i = 1; i <= n; i++) {
            suma += semn * b;
            semn = -semn;  // Schimbă semnul
    
            int c = a + b;
            a = b;
            b = c;
        }
    
        cout << "Suma alternanta: " << suma << endl;
        return 0;
    }

    Exercițiul 3: Numerele Fibonacci mai mici decât N

    #include <iostream>
    using namespace std;
    
    int main() {
        int N = 100;
    
        cout << "Numere Fibonacci < " << N << ":\n";
    
        int a = 0, b = 1;
    
        while(a < N) {
            cout << a << " ";
    
            int c = a + b;
            a = b;
            b = c;
        }
    
        return 0;
    }

    În concluzie:

    • Fibonacci se calculează cel mai bine iterativ
    • Formulele pentru sume economisesc timp de calcul
    • Recurența F(n) = F(n-1) + F(n-2) e esența șirului

    Reguli importante:

    1. Pentru Fibonacci, mereu începe cu F(0)=0, F(1)=1
    2. Varianta iterativă e mereu mai rapidă decât cea recursivă
    3. Când ai o formulă pentru termen general, folosește-o pentru sume!
  • Divizibilitate, Numere Prime și Algoritmul lui Euclid

    Bun, hai să vorbim despre trei concepte matematice fundamentale în programare: DIVIZIBILITATEA, NUMERELE PRIME și ALGORITMUL LUI EUCLID. Nu sunt doar teorie matematică – sunt instrumente practice pe care le folosești în criptografie, optimizare și multe altele.

    1. Divizibilitate: “Când un Număr se Împarte Exact”

    Definiție: Un număr a este divizibil cu b dacă restul împărțirii a la b este 0.

    #include <iostream>
    using namespace std;
    
    int main() {
        int a = 15, b = 5;
    
        if(a % b == 0) {  // Operatorul % dă restul
            cout << a << " este divizibil cu " << b << endl;
        } else {
            cout << a << " NU este divizibil cu " << b << endl;
        }
    
        return 0;
    }

    Proprietăți importante:

    • Orice număr e divizibil cu 1 și cu el însuși
    • 0 e divizibil cu orice număr (dar NU poți împărți la 0!)
    • Dacă a e divizibil cu b și b cu c, atunci a e divizibil cu c

    2. Numere Prime: “Atomii” Numerelor

    Definiție: Număr prim = număr mai mare ca 1 care are DOAR doi divizori: 1 și el însuși.

    #include <iostream>
    using namespace std;
    
    int main() {
        int n = 17;
        bool estePrim = true;
    
        if(n <= 1) {
            estePrim = false;  // 0 și 1 nu sunt prime
        } else {
            // Verifică divizorii de la 2 până la n/2
            for(int i = 2; i <= n/2; i++) {
                if(n % i == 0) {  // Dacă găsim un divizor
                    estePrim = false;
                    break;
                }
            }
        }
    
        if(estePrim) {
            cout << n << " este numar prim!" << endl;
        } else {
            cout << n << " NU este numar prim!" << endl;
        }
    
        return 0;
    }

    Optimizare 1: Verifică doar până la √n

    #include <iostream>
    #include <cmath>  // pentru sqrt()
    using namespace std;
    
    int main() {
        int n = 17;
        bool estePrim = true;
    
        if(n <= 1) {
            estePrim = false;
        } else {
            int limita = sqrt(n);  // √17 ≈ 4.12
    
            for(int i = 2; i <= limita; i++) {
                if(n % i == 0) {
                    estePrim = false;
                    break;
                }
            }
        }
    
        cout << n << (estePrim ? " este" : " NU este") << " prim" << endl;
        return 0;
    }

    Optimizare 2: Verifică doar numerele impare (dacă n > 2)

    #include <iostream>
    #include <cmath>
    using namespace std;
    
    int main() {
        int n = 17;
        bool estePrim = true;
    
        if(n <= 1) {
            estePrim = false;
        } else if(n == 2) {
            estePrim = true;  // 2 e prim
        } else if(n % 2 == 0) {
            estePrim = false;  // Numerele pare mai mari ca 2 nu sunt prime
        } else {
            int limita = sqrt(n);
    
            for(int i = 3; i <= limita; i += 2) {  // Doar impare
                if(n % i == 0) {
                    estePrim = false;
                    break;
                }
            }
        }
    
        cout << n << (estePrim ? " este" : " NU este") << " prim" << endl;
        return 0;
    }

    3. Generarea Numerelor Prime: “Ciurul lui Eratostene”

    Algoritm inteligent pentru a găsi toate numerele prime până la o limită.

    #include <iostream>
    using namespace std;
    
    int main() {
        const int N = 30;
        bool estePrim[N+1];  // Vector de adevăr
    
        // Inițial, presupunem că toate sunt prime
        for(int i = 0; i <= N; i++) {
            estePrim[i] = true;
        }
    
        // 0 și 1 nu sunt prime
        estePrim[0] = estePrim[1] = false;
    
        // Ciurul lui Eratostene
        for(int i = 2; i * i <= N; i++) {
            if(estePrim[i]) {  // Dacă i e prim
                // Marchează multiplii lui i ca neprime
                for(int j = i * i; j <= N; j += i) {
                    estePrim[j] = false;
                }
            }
        }
    
        // Afișează numerele prime
        cout << "Numere prime pana la " << N << ":\n";
        for(int i = 2; i <= N; i++) {
            if(estePrim[i]) {
                cout << i << " ";
            }
        }
    
        return 0;
    }

    4. Descompunerea în Factori Primi

    Teorema fundamentală a aritmeticii: Orice număr întreg > 1 poate fi scris ca produs de numere prime.

    #include <iostream>
    using namespace std;
    
    int main() {
        int n = 60;
        cout << n << " = ";
    
        int copie = n;
    
        // Împarte succesiv la factori primi
        for(int divizor = 2; divizor * divizor <= copie; divizor++) {
            while(copie % divizor == 0) {  // Cât timp se împarte exact
                cout << divizor;
                copie /= divizor;
    
                if(copie > 1) {
                    cout << " * ";
                }
            }
        }
    
        // Dacă a rămas ceva, e un număr prim
        if(copie > 1) {
            cout << copie;
        }
    
        cout << endl;
        return 0;
    }

    5. Algoritmul lui Euclid: “Cel Mai Mare Divizor Comun”

    CMMDC = cel mai mare număr care divide două numere fără rest.

    Algoritmul lui Euclid (scăderi repetate):

    #include <iostream>
    using namespace std;
    
    int main() {
        int a = 48, b = 18;
    
        while(a != b) {
            if(a > b) {
                a = a - b;  // Scade pe cel mic din cel mare
            } else {
                b = b - a;
            }
        }
    
        cout << "CMMDC(48, 18) = " << a << endl;
        return 0;
    }

    Algoritmul lui Euclid (împărțiri repetate) – VERSIUNEA OPTIMĂ:

    #include <iostream>
    using namespace std;
    
    int main() {
        int a = 48, b = 18;
        int copieA = a, copieB = b;
    
        while(b != 0) {
            int rest = a % b;
            a = b;
            b = rest;
        }
    
        cout << "CMMDC(" << copieA << ", " << copieB << ") = " << a << endl;
        return 0;
    }

    Cum funcționează:

    a=48, b=18
    rest = 48 % 18 = 12
    a=18, b=12
    
    rest = 18 % 12 = 6  
    a=12, b=6
    
    rest = 12 % 6 = 0
    a=6, b=0 → STOP
    
    CMMDC = 6

    6. Cel Mai Mic Multiplu Comun (CMMMC)

    Formula: CMMMC(a,b) = (a × b) / CMMDC(a,b)

    #include <iostream>
    using namespace std;
    
    int cmmdc(int a, int b) {
        while(b != 0) {
            int rest = a % b;
            a = b;
            b = rest;
        }
        return a;
    }
    
    int main() {
        int a = 12, b = 18;
        int d = cmmdc(a, b);
        int m = (a * b) / d;  // CMMMC
    
        cout << "CMMMC(" << a << ", " << b << ") = " << m << endl;
        return 0;
    }

    7. Numere Prime Între Ele (Relativ Prime)

    Două numere sunt prime între ele dacă CMMDC = 1.

    #include <iostream>
    using namespace std;
    
    int main() {
        int a = 8, b = 15;
    
        // Calcul CMMDC
        int x = a, y = b;
        while(y != 0) {
            int rest = x % y;
            x = y;
            y = rest;
        }
    
        if(x == 1) {
            cout << a << " si " << b << " sunt prime intre ele" << endl;
        } else {
            cout << a << " si " << b << " NU sunt prime intre ele" << endl;
        }
    
        return 0;
    }

    8. Aplicații Practice

    Aplicația 1: Simplificare fracție

    #include <iostream>
    using namespace std;
    
    int cmmdc(int a, int b) {
        while(b != 0) {
            int r = a % b;
            a = b;
            b = r;
        }
        return a;
    }
    
    int main() {
        int numarator = 24, numitor = 36;
        int d = cmmdc(numarator, numitor);
    
        cout << numarator << "/" << numitor << " = ";
        cout << (numarator/d) << "/" << (numitor/d) << endl;
    
        return 0;
    }

    Aplicația 2: Verifică dacă un număr e perfect
    Număr perfect = suma divizorilor săi (fără el însuși) e egală cu numărul.

    #include <iostream>
    using namespace std;
    
    int main() {
        int n = 28;
        int sumaDivizori = 0;
    
        for(int i = 1; i <= n/2; i++) {
            if(n % i == 0) {
                sumaDivizori += i;
            }
        }
    
        if(sumaDivizori == n) {
            cout << n << " este numar perfect!" << endl;
        } else {
            cout << n << " NU este numar perfect" << endl;
        }
    
        return 0;
    }

    Aplicația 3: Numere prime gemene
    Două numere prime sunt gemene dacă diferența dintre ele este 2.

    #include <iostream>
    #include <cmath>
    using namespace std;
    
    bool estePrim(int n) {
        if(n <= 1) return false;
        if(n == 2) return true;
        if(n % 2 == 0) return false;
    
        int limita = sqrt(n);
        for(int i = 3; i <= limita; i += 2) {
            if(n % i == 0) return false;
        }
        return true;
    }
    
    int main() {
        cout << "Primele perechi de numere prime gemene:\n";
    
        for(int i = 2; i <= 50; i++) {
            if(estePrim(i) && estePrim(i + 2)) {
                cout << "(" << i << ", " << i+2 << ")\n";
            }
        }
    
        return 0;
    }

    9. Exerciții Practice

    Exercițiul 1: Completează algoritmul

    int a = 36, b = 48;
    int cmmdc;
    
    // Calculează CMMDC folosind algoritmul lui Euclid
    while(/* condiție */) {
        int rest = /* calcul rest */;
        a = b;
        b = /* ce pui aici? */;
    }
    
    cmmdc = a;

    Soluție:

    while(b != 0) {
        int rest = a % b;
        a = b;
        b = rest;
    }

    Exercițiul 2: Ce verifică acest cod?

    int n = 29;
    bool ok = true;
    
    for(int i = 2; i * i <= n; i++) {
        if(n % i == 0) {
            ok = false;
            break;
        }
    }

    Răspuns: Verifică dacă n este număr prim.

    Exercițiul 3: Găsește toți divizorii unui număr

    int n = 36;
    cout << "Divizorii lui " << n << ":\n";
    
    for(int i = 1; i <= /* până unde? */; i++) {
        if(n % i == 0) {
            cout << i << " ";
            if(i != n/i) {  // Evită dublarea pentru pătrate perfecte
                cout << n/i << " ";
            }
        }
    }

    Soluție: i <= sqrt(n) sau i * i <= n

    În concluzie:

    • Divizibilitatea se testează cu % (restul împărțirii)
    • Numerele prime sunt fundamentul aritmeticii
    • Algoritmul lui Euclid e cel mai eficient mod de a calcula CMMDC

    Reguli importante:

    1. Orice algoritm cu numere prime începe cu verificarea cazurilor speciale (0, 1, 2)
    2. Pentru verificarea primalității, verifică doar până la √n
    3. Pentru CMMDC, folosește algoritmul lui Euclid cu împărțiri (nu scăderi)