1/4
</> Informatica liceu

Informatica clasa 9

Lecția 1 ⏱ 120 min

Curs Complet de Informatică — Clasa a IX-a

Specializarea: Matematică-Informatică (Curriculum de Specialitate)
Limbaje: Python (principal) și C++ (secundar)


📋 Cuprins

  1. Introducere
  2. Capitolul 1: Principii de elaborare a unui program
  3. Capitolul 2: Prelucrări ale numerelor
  4. Capitolul 3: Subprograme
  5. Capitolul 4: Introducere în programarea orientată pe obiecte
  6. Capitolul 5: Interfețe grafice (Tkinter)
  7. Capitolul 6: Fișiere text
  8. Capitolul 7: Modelul conceptual liniar — lista
  9. Capitolul 8: Clasa list din Python și vectori în C++
  10. Capitolul 9: Generarea sistematică a elementelor unei liste
  11. Capitolul 10: Metode de sortare
  12. Anexe

Introducere

Despre acest curs

Acest curs acoperă integral programa școlară de informatică pentru clasa a IX-a, specializarea matematică-informatică (Ordin MEC 4.350/2025). Conținutul este structurat în ordinea recomandată de programă și include:

  • Noțiuni teoretice explicate riguros și cu exemple intuitive.
  • Cod sursă în Python (limbaj principal) și C++ (limbaj secundar, pentru clasele intensive).
  • Probleme rezolvate din viața reală.
  • Exerciții propuse la finalul fiecărui capitol.

Competențele formate

Programa vizează 6 competențe generale (CG) derivate din taxonomia Bloom:

CG Nivel cognitiv Descriere
CG1 Identificare Recunoașterea caracteristicilor modelelor
CG2 Înțelegere Explicarea principiilor
CG3 Aplicare Utilizarea modelelor în soluții
CG4 Analiză Compararea soluțiilor
CG5 Evaluare Aprecierea corectitudinii și eficienței
CG6 Creare Elaborarea de algoritmi personalizați

De ce Python + C++?

  • Python este limbajul de bază: sintaxă simplă, concentrare pe logică, potrivit pentru învățarea conceptelor fundamentale.
  • C++ aprofundează mecanismele interne: gestionarea memoriei, tipuri stricte, eficiență ridicată — esențial pentru olimpiade și studii avansate.

Medii de dezvoltare recomandate

Pentru Python: PyCharm (Community/Educational), IDLE, Spyder, VS Code.
Pentru C++: Code::Blocks, VS Code (cu extensia C/C++), Visual Studio.
Online: OnlineGDB, Programiz, Repl.it.


Capitolul 1: Principii de elaborare a unui program

1.1. Gândirea computațională

Gândirea computațională reprezintă ansamblul de procese mentale folosite pentru a formula probleme și soluții într-o formă pe care un calculator (sau un om) le poate executa.

Cele 4 pilonii ai gândirii computaționale:

  1. Descompunere (Decomposition) — împărțirea unei probleme complexe în subprobleme mai simple.
  2. Recunoașterea tiparelor (Pattern Recognition) — identificarea asemănărilor între probleme.
  3. Abstractizare (Abstraction) — reținerea detaliilor esențiale, ignorarea celor irelevante.
  4. Proiectarea algoritmilor (Algorithm Design) — elaborarea pașilor concreți de rezolvare.

Exemplu intuitiv: Pregătirea unui sandwich.

  • Descompunere: prăjim pâinea, ungem unt, adăugăm brânza, adăugăm legumele.
  • Tipare: toate sandwich-urile au o bază (pâine) + umplutură.
  • Abstractizare: nu contează culoarea farfuriei.
  • Algoritm: pași secvențiali cu decizii („dacă brânza e topită, scoate din cuptor”).

1.2. Etapele elaborării unui program

Orice program parcurge 5 etape fundamentale:

┌──────────┐   ┌───────────┐   ┌────────────────┐   ┌──────────┐   ┌─────────┐
│ ANALIZĂ  │ → │ PROIECTARE│ → │ IMPLEMENTARE   │ → │ TESTARE  │ → │DEPANARE │
└──────────┘   └───────────┘   └────────────────┘   └──────────┘   └─────────┘
  1. Analiza problemei — ce date avem (intrare), ce vrem să obținem (ieșire), ce constrângeri există.
  2. Proiectarea algoritmului — reprezentare prin pseudocod/schemă logică, descompunere modulară.
  3. Implementarea — scrierea codului într-un limbaj de programare.
  4. Testarea — verificarea cu date de intrare diverse (inclusiv cazuri limită).
  5. Depanarea (debugging) — identificarea și corectarea erorilor.

1.3. Tipuri de erori

Tip de eroare Când apare Exemplu
Sintactică La compilare/interpretare Lipsă : în Python sau ; în C++
De logică Programul rulează dar rezultatul e greșit Am scris < în loc de <=
De executare (runtime) În timpul rulării Împărțire la zero, index în afara listei

1.4. Moduri de reprezentare a algoritmilor

a) Scheme logice (blocuri grafice)

Conform programei, simbolurile standard sunt:

Simbol Rol
Dreptunghi Bloc de proces (calcul, atribuire)
Romb Bloc de decizie (2 ieșiri: Da/Nu)
Paralelogram Intrare/ieșire date
Elipsă START / STOP
Săgeată Linie de flux

b) Pseudocod

Limbaj intermediar, apropiat de limba naturală, independent de orice limbaj de programare.

Exemplu: citește două numere și afișează maximul.

START
  citește a, b
  dacă a > b atunci
    scrie a
  altfel
    scrie b
  sfârșit dacă
STOP

c) Limbaje de programare

  • Nivel înalt (Python, C++, Java) — apropiate de limbajul uman.
  • Nivel scăzut (Assembly) — apropiate de limbajul mașinii.

Interpretor vs. Compilator:

  • Interpretor (Python): execută codul linie cu linie.
  • Compilator (C++): traduce tot codul în cod mașină înainte de execuție.

1.5. Primul program

Python

# Afișează un mesaj de întâmpinare
print("Bună, lume!")
print("Bine ai venit la informatică!")

C++

#include <iostream>
using namespace std;

int main() {
    cout << "Bună, lume!" << endl;
    cout << "Bine ai venit la informatică!" << endl;
    return 0;
}

1.6. Variabile și tipuri de date

O variabilă este o locație de memorie cu un nume, care stochează o valoare.

Tipuri de bază — comparație

Concept Python C++
Întreg int (nelimitat) int (32 biți), long long (64 biți)
Real float float, double
Caracter str (lungime 1) char
Șir str string, char[]
Logic bool (True/False) bool (true/false)

Python — tipizare dinamică

varsta = 15          # int
pi = 3.14159         # float
nume = "Alex"        # str
este_elev = True     # bool

# Variabila poate schimba tipul
x = 10
x = "acum sunt text"  # Legal în Python

C++ — tipizare statică

#include <iostream>
#include <string>
using namespace std;

int main() {
    int varsta = 15;
    double pi = 3.14159;
    string nume = "Alex";
    bool este_elev = true;

    // varsta = "text";  // EROARE de compilare!
    return 0;
}

1.7. Citirea și scrierea datelor

Python

# Citire
nume = input("Introdu numele: ")
varsta = int(input("Introdu vârsta: "))
nota = float(input("Introdu nota: "))

# Afișare
print("Salut,", nume)
print(f"Ai {varsta} ani și nota {nota}")

C++

#include <iostream>
#include <string>
using namespace std;

int main() {
    string nume;
    int varsta;
    double nota;

    cout << "Introdu numele: ";
    cin >> nume;
    cout << "Introdu vârsta: ";
    cin >> varsta;
    cout << "Introdu nota: ";
    cin >> nota;

    cout << "Salut, " << nume << endl;
    cout << "Ai " << varsta << " ani și nota " << nota << endl;
    return 0;
}

1.8. Operatori

Operatori aritmetici

Op. Python C++ Exemplu
Adunare + + 5+3=8
Scădere - - 5-3=2
Înmulțire * * 5*3=15
Împărțire reală / / (cu double) 5/2=2.5
Împărțire întreagă // / (cu int) 5//2=2
Modulo (rest) % % 5%2=1
Putere ** pow(a,b) 2**3=8

Operatori relaționali

Ambele limbaje folosesc: ==, !=, <, >, <=, >=.

Operatori logici

Operație Python C++
ȘI logic and &&
SAU logic or ||
NU logic not !

1.9. Structuri de control

a) Structura decizională (if)

Python:

nota = float(input("Nota: "))
if nota >= 5:
    print("Promovat")
else:
    print("Nepromovat")

# if-elif-else
if nota >= 9:
    print("Excelent")
elif nota >= 7:
    print("Bine")
elif nota >= 5:
    print("Satisfăcător")
else:
    print("Nepromovat")

C++:

double nota;
cin >> nota;
if (nota >= 5) {
    cout << "Promovat";
} else {
    cout << "Nepromovat";
}

// if-else if-else
if (nota >= 9) cout << "Excelent";
else if (nota >= 7) cout << "Bine";
else if (nota >= 5) cout << "Satisfăcător";
else cout << "Nepromovat";

b) Structura repetitivă cu test inițial (while)

Python:

# Afișează numerele de la 1 la 10
i = 1
while i <= 10:
    print(i)
    i += 1

C++:

int i = 1;
while (i <= 10) {
    cout << i << " ";
    i++;
}

c) Structura repetitivă cu test final (do-while)

Python nu are do-while, dar îl putem simula:

while True:
    n = int(input("Numărul (>0): "))
    if n > 0:
        break

C++:

int n;
do {
    cout << "Numărul (>0): ";
    cin >> n;
} while (n <= 0);

d) Structura repetitivă cu contor (for)

Python:

# range(start, stop, step) — stop este exclus
for i in range(1, 11):        # 1, 2, ..., 10
    print(i)

for i in range(10, 0, -1):    # 10, 9, ..., 1
    print(i)

for i in range(0, 20, 2):     # 0, 2, 4, ..., 18
    print(i)

C++:

for (int i = 1; i <= 10; i++)
    cout << i << " ";

for (int i = 10; i >= 1; i--)
    cout << i << " ";

for (int i = 0; i < 20; i += 2)
    cout << i << " ";

1.10. Eficiența algoritmilor — notația O

Complexitatea temporală exprimă cum crește numărul de operații în funcție de dimensiunea datelor (notată n).

Notație Denumire Exemplu
O(1) Constantă Acces la un element din listă prin index
O(log n) Logaritmică Căutare binară
O(n) Liniară Parcurgerea unui tablou
O(n log n) Liniar-logaritmică Sortare eficientă (MergeSort)
O(n²) Pătratică Metoda bulelor, selecția minimului
O(2ⁿ) Exponențială Fibonacci recursiv fără memorare

Exemplu — calcularea ordinului:

# O(n) — o singură buclă
for i in range(n):
    print(i)

# O(n²) — bucle imbricate
for i in range(n):
    for j in range(n):
        print(i, j)

1.11. Testarea programelor

Un program bun trebuie testat cu:

  • Date tipice (cazuri obișnuite).
  • Cazuri limită (valori minime, maxime, listă vidă, un element).
  • Date invalide (pentru a verifica validarea).

Exemplu: pentru un program care calculează media a n note, testăm:

  • n = 1 (un singur element).
  • n = 0 (listă vidă — ar trebui să afișeze eroare).
  • Note la limită: 1 și 10.
  • Medie fracționară: note = [7, 8] → media = 7.5.

✏️ Exerciții propuse — Capitolul 1

  1. Scrie un program care citește 3 numere și afișează suma, produsul și media lor.
  2. Citește un număr și verifică dacă este par sau impar.
  3. Citește un an și stabilește dacă este bisect (divizibil cu 4, dar nu cu 100 — sau divizibil cu 400).
  4. Afișează tabla înmulțirii pentru un număr citit.
  5. Calculează n! (factorial) pentru un n citit.

Capitolul 2: Prelucrări ale numerelor

2.1. Operații cu cifrele unui număr

Acces la ultima cifră

Ultima cifră a unui număr n = n % 10.

Eliminarea ultimei cifre

n // 10 (Python) sau n / 10 (C++ cu int).

Adăugarea unei cifre la dreapta

Dacă avem numărul n și vrem să adăugăm cifra c la dreapta: n = n * 10 + c.

Exemplu: n = 25, c = 7n = 25*10 + 7 = 257.

Adăugarea unei cifre la stânga

Dacă n are k cifre: n = c * 10^k + n.

Exemplu: n = 25 (2 cifre), c = 7n = 7*100 + 25 = 725.

2.2. Parcurgerea cifrelor unui număr

Python

def afiseaza_cifre(n):
    """Afișează cifrele unui număr, de la dreapta la stânga."""
    while n > 0:
        print(n % 10, end=" ")
        n //= 10

afiseaza_cifre(12345)  # 5 4 3 2 1

C++

void afiseaza_cifre(int n) {
    while (n > 0) {
        cout << n % 10 << " ";
        n /= 10;
    }
}

2.3. Oglinditul unui număr

Oglinditul lui 1234 este 4321.

Python

def oglindit(n):
    o = 0
    while n > 0:
        o = o * 10 + n % 10
        n //= 10
    return o

print(oglindit(1234))  # 4321
print(oglindit(100))   # 1 (zerourile de la sfârșit se pierd!)

C++

int oglindit(int n) {
    int o = 0;
    while (n > 0) {
        o = o * 10 + n % 10;
        n /= 10;
    }
    return o;
}

⚠️ Observație: oglindit(oglindit(n)) NU este întotdeauna egal cu n! Exemplu: oglindit(100) = 1, iar oglindit(1) = 1 ≠ 100.

2.4. Suma și numărul cifrelor

def suma_cifrelor(n):
    s = 0
    while n > 0:
        s += n % 10
        n //= 10
    return s

def numar_cifre(n):
    nr = 0
    while n > 0:
        nr += 1
        n //= 10
    return nr

print(suma_cifrelor(1234))  # 10
print(numar_cifre(1234))    # 4
int suma_cifrelor(int n) {
    int s = 0;
    while (n > 0) { s += n % 10; n /= 10; }
    return s;
}

int numar_cifre(int n) {
    int nr = 0;
    while (n > 0) { nr++; n /= 10; }
    return nr;
}

2.5. Eliminarea unor cifre dintr-un număr

Problema: Dintr-un număr, să eliminăm toate cifrele impare, păstrând ordinea.

def elimina_impare(n):
    rezultat = 0
    putere = 1
    # Parcurgem cifrele de la dreapta la stânga
    cifre_pastrate = []
    while n > 0:
        c = n % 10
        if c % 2 == 0:
            cifre_pastrate.append(c)
        n //= 10
    # Reconstruim numărul
    for c in reversed(cifre_pastrate):
        rezultat = rezultat * 10 + c
    return rezultat

print(elimina_impare(123456))  # 246
print(elimina_impare(2040))    # 2040

2.6. Divizorii unui număr

Un divizor al lui n este un număr d astfel încât n % d == 0.

Metoda 1 — parcurgere până la n (O(n))

def divizori_v1(n):
    for d in range(1, n + 1):
        if n % d == 0:
            print(d, end=" ")

Metoda 2 — parcurgere până la n/2 + n (O(n/2))

def divizori_v2(n):
    for d in range(1, n // 2 + 1):
        if n % d == 0:
            print(d, end=" ")
    print(n)  # n este întotdeauna divizor al lui n

Metoda 3 — parcurgere până la √n (O(√n)) ⭐

import math
def divizori_v3(n):
    for d in range(1, int(math.sqrt(n)) + 1):
        if n % d == 0:
            print(d, end=" ")
            if d != n // d:
                print(n // d, end=" ")

De ce √n? Dacă d este divizor și d ≤ √n, atunci n/d ≥ √n. Deci toți divizorii apar în perechi (d, n/d).

C++ — Metoda √n

#include <cmath>
void divizori(int n) {
    for (int d = 1; d * d <= n; d++) {
        if (n % d == 0) {
            cout << d << " ";
            if (d != n / d)
                cout << n / d << " ";
        }
    }
}

2.7. Numere prime

Un număr n > 1 este prim dacă are exact 2 divizori: 1 și n.

def este_prim(n):
    if n < 2:
        return False
    for d in range(2, int(n**0.5) + 1):
        if n % d == 0:
            return False
    return True

print(este_prim(7))   # True
print(este_prim(15))  # False
bool este_prim(int n) {
    if (n < 2) return false;
    for (int d = 2; d * d <= n; d++)
        if (n % d == 0) return false;
    return true;
}

2.8. Descompunerea în factori primi

def descompunere(n):
    d = 2
    while n > 1:
        while n % d == 0:
            print(d, end=" ")
            n //= d
        d += 1

descompunere(60)  # 2 2 3 5  (pentru că 60 = 2²·3·5)

2.9. Algoritmul lui Euclid — CMMDC

Cel mai mare divizor comun al două numere a și b se poate calcula eficient folosind algoritmul lui Euclid.

a) Cu scăderi repetate

Cât timp a ≠ b:
    dacă a > b: a = a - b
    altfel:      b = b - a
CMMDC = a
def cmmdc_scaderi(a, b):
    while a != b:
        if a > b:
            a -= b
        else:
            b -= a
    return a

b) Cu împărțiri repetate (mai eficient — O(log n))

Cât timp b ≠ 0:
    r = a % b
    a = b
    b = r
CMMDC = a
def cmmdc(a, b):
    while b != 0:
        a, b = b, a % b
    return a

print(cmmdc(48, 18))  # 6
int cmmdc(int a, int b) {
    while (b != 0) {
        int r = a % b;
        a = b;
        b = r;
    }
    return a;
}

2.10. CMMMC — Cel mai mic multiplu comun

Relația fundamentală: a * b = cmmdc(a,b) * cmmmc(a,b).

def cmmmc(a, b):
    return a * b // cmmdc(a, b)

print(cmmmc(4, 6))  # 12

Problemă practică: Două semafoare durează 30s, respectiv 45s. După cât timp se sincronizează?
Răspuns: cmmmc(30, 45) = 90 secunde.

2.11. Conversia între baze de numerație

Din baza 10 în baza 2 (sau oricare b)

Algoritm: împărțim succesiv la b și citim resturile în ordine inversă.

25 : 2 = 12 rest 1
12 : 2 =  6 rest 0
 6 : 2 =  3 rest 0
 3 : 2 =  1 rest 1
 1 : 2 =  0 rest 1

Citit invers: 1100125₁₀ = 11001₂.

def baza_10_la_b(n, b):
    if n == 0:
        return "0"
    cifre = []
    while n > 0:
        cifre.append(str(n % b))
        n //= b
    return "".join(reversed(cifre))

print(baza_10_la_b(25, 2))   # 11001
print(baza_10_la_b(255, 16)) # FF? — doar cifre! Pentru hexa ar fi nevoie de conversie

Din baza b în baza 10

Algoritm (Horner): 11001₂ = 1·2⁴ + 1·2³ + 0·2² + 0·2¹ + 1·2⁰ = 25

def baza_b_la_10(s, b):
    rezultat = 0
    for c in s:
        rezultat = rezultat * b + int(c)
    return rezultat

print(baza_b_la_10("11001", 2))  # 25

✏️ Exerciții propuse — Capitolul 2

  1. Citește un număr și afișează suma cifrelor sale.
  2. Verifică dacă un număr este palindrom (ex: 12321).
  3. Afișează toți divizorii unui număr folosind metoda O(√n).
  4. Verifică dacă un număr este perfect (suma divizorilor proprii = n). Exemplu: 6 = 1+2+3.
  5. Calculează CMMDC pentru 3 numere.
  6. Transformă un număr din baza 10 în baza 8.
  7. Afișează toate numerele prime până la n (Ciurul lui Eratostene).

Capitolul 3: Subprograme

3.1. Ce sunt subprogramele?

Un subprogram (sau funcție) este o secvență de cod nominalizată care execută o sarcină specifică și poate fi apelată ori de câte ori este nevoie.

Analogie: O rețetă. O scrii o singură dată, dar o folosești de câte ori vrei să gătești acel preparat.

Beneficiile subprogramelor:

  • Reutilizare — scriem o dată, folosim de mai multe ori.
  • Claritate — codul devine mai ușor de citit.
  • Modularitate — împărțim problemele mari în bucăți mici.
  • Mentenanță — corectăm o eroare într-un singur loc.

3.2. Structura unui subprogram

Componente:

  1. Antet — numele și parametrii.
  2. Corp — instrucțiunile executate.
  3. Valoare returnată (opțional).

3.3. Definire și apel în Python

def saluta(nume):              # antet
    print(f"Salut, {nume}!")   # corp

saluta("Alex")   # apel
saluta("Maria")  # alt apel

Funcție cu valoare returnată:

def patrat(x):
    return x * x

rezultat = patrat(5)
print(rezultat)  # 25
print(patrat(7)) # 49

Funcție cu mai mulți parametri:

def suma(a, b):
    return a + b

def maxim(a, b):
    if a > b:
        return a
    return b

print(suma(3, 5))    # 8
print(maxim(10, 7))  # 10

3.4. Definire și apel în C++

#include <iostream>
using namespace std;

void saluta(string nume) {
    cout << "Salut, " << nume << "!" << endl;
}

int patrat(int x) {
    return x * x;
}

int maxim(int a, int b) {
    return (a > b) ? a : b;
}

int main() {
    saluta("Alex");
    cout << patrat(5) << endl;   // 25
    cout << maxim(10, 7) << endl;// 10
    return 0;
}

3.5. Variabile locale și globale

  • Variabilă locală: definită în interiorul unui subprogram. Există doar pe durata executării subprogramului.
  • Variabilă globală: definită în afara oricărui subprogram. Există pe toată durata programului.

Python

x = 10  # variabilă globală

def test():
    y = 5  # variabilă locală
    print(x + y)  # poate citi x

test()        # afișează 15
# print(y)    # EROARE — y nu există aici

def modifica():
    global x
    x = 100  # modifică variabila globală

modifica()
print(x)  # 100

C++

int x = 10;  // globală

void test() {
    int y = 5;  // locală
    cout << x + y << endl;
}

int main() {
    test();
    // cout << y;  // EROARE
    return 0;
}

3.6. Transmiterea parametrilor

Prin valoare (copie)

Parametrul primește o copie a valorii. Modificările nu se reflectă în afara funcției.

Python (pentru tipuri imutabile: int, float, str, tuple):

def modifica(x):
    x = 100
    print("În funcție:", x)

a = 5
modifica(a)
print("După apel:", a)  # 5 — neschimbat

C++:

void modifica(int x) {  // x este o copie
    x = 100;
}

int a = 5;
modifica(a);
cout << a;  // 5

Prin referință (în C++)

void modifica(int &x) {  // x este alias pentru variabila originală
    x = 100;
}

int a = 5;
modifica(a);
cout << a;  // 100 — modificat!

În Python, listele și dicționarele sunt transmise „prin referință” implicit:

def adauga(lista):
    lista.append(99)

l = [1, 2, 3]
adauga(l)
print(l)  # [1, 2, 3, 99]

3.7. Subprograme predefinite — matematice

Python

import math

abs(-5)         # 5
round(3.7)      # 4
round(3.14, 1)  # 3.1
int(3.9)        # 3 (trunchiere)
math.sqrt(16)   # 4.0
math.floor(3.7) # 3
math.ceil(3.2)  # 4
math.pow(2, 10) # 1024.0

C++

#include <cmath>

abs(-5);          // 5
round(3.7);       // 4
(int)3.9;         // 3
sqrt(16);         // 4.0
floor(3.7);       // 3
ceil(3.2);        // 4
pow(2, 10);       // 1024

3.8. Subprograme predefinite — conversii

int("42")        # 42
int("FF", 16)    # 255 (conversie din hexa)
float("3.14")    # 3.14
str(42)          # "42"
bool(0)          # False
bool(1)          # True

3.9. Subprograme predefinite — colecții

Funcții foarte utile pentru liste și alte colecții:

lista = [3, 7, 2, 8, 1]

len(lista)   # 5  — numărul de elemente
min(lista)   # 1  — minimul
max(lista)   # 8  — maximul
sum(lista)   # 21 — suma
sorted(lista) # [1, 2, 3, 7, 8] — listă sortată (nouă)

3.10. Problemă rezolvată — calculator de note

def media(note):
    return sum(note) / len(note)

def nota_maxima(note):
    return max(note)

def afiseaza_raport(nume_elev, note):
    print(f"Elev: {nume_elev}")
    print(f"  Note: {note}")
    print(f"  Medie: {media(note):.2f}")
    print(f"  Maxim: {nota_maxima(note)}")
    print(f"  Minim: {min(note)}")

note_alex = [9, 10, 8, 7, 9]
afiseaza_raport("Alex", note_alex)
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <string>
using namespace std;

double media(vector<int>& note) {
    return (double)accumulate(note.begin(), note.end(), 0) / note.size();
}

int nota_maxima(vector<int>& note) {
    return *max_element(note.begin(), note.end());
}

void afiseaza_raport(string nume, vector<int>& note) {
    cout << "Elev: " << nume << endl;
    cout << "  Medie: " << media(note) << endl;
    cout << "  Maxim: " << nota_maxima(note) << endl;
}

int main() {
    vector<int> note_alex = {9, 10, 8, 7, 9};
    afiseaza_raport("Alex", note_alex);
    return 0;
}

✏️ Exerciții propuse — Capitolul 3

  1. Scrie o funcție care primește un număr și returnează suma cifrelor sale.
  2. Scrie o funcție este_prim(n) și folosește-o pentru a afișa toate numerele prime de la 1 la 100.
  3. Scrie o funcție distanta(x1, y1, x2, y2) care calculează distanța euclidiană.
  4. Scrie un mini-calculator cu funcții pentru +, -, *, /.
  5. Scrie o funcție care primește o listă și returnează media fără a folosi sum().

Capitolul 4: Introducere în programarea orientată pe obiecte

4.1. Concepte fundamentale

Programarea orientată pe obiecte (POO) modelează realitatea prin obiecte care au:

  • Proprietăți (atribute/date) — ce știe obiectul despre sine.
  • Comportamente (metode) — ce poate face obiectul.

Analogie: Un câine are:

  • Proprietăți: nume, rasă, vârstă, culoare.
  • Comportamente: latră, mănâncă, aleargă.

4.2. Clasă vs. Obiect

  • Clasa este un șablon (un plan arhitectural).
  • Obiectul este o instanță concretă a clasei (o clădire construită după plan).
Clasa: Mașină                    Obiecte (instanțe):
  - culoare                      mașina lui Alex: roșie, Dacia, 2020
  - marcă                        mașina Mariei:  albastră, BMW, 2022
  - an

4.3. Utilizarea claselor predefinite

La clasa a IX-a folosim în principal clase predefinite, nu le creăm noi. Exemple de clase deja disponibile:

Python

# Clasa str (șiruri de caractere)
s = "Alex"             # instanțiere implicită
print(s.upper())       # "ALEX" — metodă
print(s.lower())       # "alex"
print(len(s))          # 4 — funcție predefinită

# Clasa list
lista = [1, 2, 3]
lista.append(4)        # metodă
print(lista)           # [1, 2, 3, 4]

# Clasa dict
persoana = {"nume": "Alex", "varsta": 15}
print(persoana["nume"])  # "Alex"

Accesul la membri

  • Atribute se accesează prin obiect.atribut.
  • Metode se apelează prin obiect.metoda().

4.4. Exemplu — clasa list folosită orientat-obiect

# Crearea obiectului (instanțiere)
numere = [5, 3, 8, 1, 9]

# Apelul metodelor
numere.append(100)    # adaugă 100 la final
numere.sort()         # sortează crescător
numere.reverse()      # inversează
numere.pop()          # elimină ultimul

# Accesul la informații
print(len(numere))    # dimensiunea
print(numere.count(3)) # numărul de apariții ale lui 3

4.5. Biblioteci

O bibliotecă (sau modul) este o colecție de clase și funcții utile.

Python — bibliotecile se importă cu import:

import math        # biblioteca matematică
import random      # numere aleatoare
import datetime    # lucru cu date și timp

print(math.pi)                # 3.141592...
print(random.randint(1, 100)) # număr aleator între 1 și 100
print(datetime.datetime.now())# data și ora curentă

C++ — bibliotecile se includ cu #include:

#include <iostream>   // pentru cout, cin
#include <cmath>      // pentru funcții matematice
#include <string>     // pentru clasa string
#include <vector>     // pentru clasa vector
#include <algorithm>  // pentru sort, max_element, etc.

4.6. Exemplu practic — utilizarea clasei datetime

from datetime import datetime, timedelta

# Obiect reprezentând data curentă
acum = datetime.now()
print(acum)

# Atribute
print(acum.year)     # anul
print(acum.month)    # luna
print(acum.day)      # ziua

# Operații
peste_o_sapt = acum + timedelta(days=7)
print(peste_o_sapt)

✏️ Exerciții propuse — Capitolul 4

  1. Folosind clasa str, citește un șir și afișează-l cu majuscule, apoi cu litere mici.
  2. Folosind biblioteca random, simulează aruncarea a două zaruri de 10 ori.
  3. Folosind math, calculează aria și circumferința unui cerc de rază dată.

Capitolul 5: Interfețe grafice (Tkinter)

5.1. De ce interfețe grafice?

Până acum am folosit interfață de tip consolă (text). Interfața grafică (GUI) oferă:

  • Ferestre, butoane, casete de text.
  • Experiență vizuală mai bună.
  • Programul este „user-friendly”.

5.2. Primul program cu Tkinter

tkinter este biblioteca standard Python pentru GUI.

import tkinter as tk

# Crearea ferestrei principale
fereastra = tk.Tk()
fereastra.title("Prima mea aplicație")
fereastra.geometry("400x300")  # lățime x înălțime

# Pornirea buclei de evenimente
fereastra.mainloop()

5.3. Label — etichete

import tkinter as tk

fereastra = tk.Tk()
fereastra.title("Salut")

eticheta = tk.Label(fereastra, text="Bună, lume!", font=("Arial", 20))
eticheta.pack(pady=20)

fereastra.mainloop()

5.4. Button — butoane

import tkinter as tk

def la_apasare():
    eticheta.config(text="Ai apăsat butonul!")

fereastra = tk.Tk()
fereastra.geometry("300x200")

eticheta = tk.Label(fereastra, text="Apasă butonul de mai jos")
eticheta.pack(pady=10)

buton = tk.Button(fereastra, text="Apasă-mă!", command=la_apasare)
buton.pack(pady=10)

fereastra.mainloop()

5.5. Entry — casete de text

import tkinter as tk

def afiseaza_salut():
    nume = caseta.get()
    eticheta_rezultat.config(text=f"Salut, {nume}!")

fereastra = tk.Tk()

tk.Label(fereastra, text="Numele tău:").pack()
caseta = tk.Entry(fereastra, width=30)
caseta.pack(pady=5)

tk.Button(fereastra, text="Salută", command=afiseaza_salut).pack(pady=5)

eticheta_rezultat = tk.Label(fereastra, text="")
eticheta_rezultat.pack(pady=10)

fereastra.mainloop()

5.6. MessageBox

import tkinter as tk
from tkinter import messagebox

def alerta():
    messagebox.showinfo("Info", "Salut!")

def intrebare():
    raspuns = messagebox.askyesno("Întrebare", "Continui?")
    print(raspuns)  # True sau False

fereastra = tk.Tk()
tk.Button(fereastra, text="Info", command=alerta).pack()
tk.Button(fereastra, text="Întrebare", command=intrebare).pack()
fereastra.mainloop()

5.7. Metode de aranjare (Layout)

Metodă Descriere
pack() Aranjare secvențială (sus, jos, stânga, dreapta)
grid() Aranjare în tabel (rânduri, coloane)
place() Poziționare absolută (x, y)

Exemplu cu grid:

import tkinter as tk

fereastra = tk.Tk()

tk.Label(fereastra, text="Nume:").grid(row=0, column=0)
tk.Entry(fereastra).grid(row=0, column=1)

tk.Label(fereastra, text="Vârstă:").grid(row=1, column=0)
tk.Entry(fereastra).grid(row=1, column=1)

tk.Button(fereastra, text="Trimite").grid(row=2, column=0, columnspan=2)

fereastra.mainloop()

5.8. Aplicație completă — calculator al divizorilor

import tkinter as tk
from tkinter import messagebox

def calculeaza_divizori():
    try:
        n = int(caseta.get())
        if n <= 0:
            messagebox.showerror("Eroare", "Introdu un număr natural pozitiv!")
            return
        divizori = [d for d in range(1, n + 1) if n % d == 0]
        rezultat.config(text=f"Divizori: {divizori}\nNumăr: {len(divizori)}")
    except ValueError:
        messagebox.showerror("Eroare", "Introdu un număr valid!")

fereastra = tk.Tk()
fereastra.title("Calculator divizori")
fereastra.geometry("400x250")

tk.Label(fereastra, text="Introdu un număr:", font=("Arial", 12)).pack(pady=10)
caseta = tk.Entry(fereastra, font=("Arial", 14))
caseta.pack(pady=5)

tk.Button(fereastra, text="Calculează divizorii",
          command=calculeaza_divizori, bg="#4CAF50", fg="white").pack(pady=10)

rezultat = tk.Label(fereastra, text="", font=("Arial", 11), wraplength=380)
rezultat.pack(pady=10)

fereastra.mainloop()

5.9. Canvas — desenare grafică

import tkinter as tk

fereastra = tk.Tk()
canvas = tk.Canvas(fereastra, width=400, height=300, bg="white")
canvas.pack()

canvas.create_rectangle(50, 50, 150, 100, fill="red")
canvas.create_oval(200, 50, 300, 150, fill="blue")
canvas.create_line(0, 200, 400, 200, fill="black", width=2)
canvas.create_text(200, 250, text="Desen cu Canvas", font=("Arial", 14))

fereastra.mainloop()

✏️ Exerciții propuse — Capitolul 5

  1. Construiește o aplicație care citește două numere din două casete și afișează suma lor la apăsarea unui buton.
  2. Realizează un „convertor de temperatură” (Celsius ↔ Fahrenheit) cu interfață grafică.
  3. Creează un quiz cu 3 întrebări cu variante de răspuns (radiobuttons).

Capitolul 6: Fișiere text

6.1. De ce fișiere?

Până acum datele introduse s-au pierdut la închiderea programului. Fișierele permit:

  • Stocarea permanentă a datelor.
  • Schimbul de date între programe.
  • Lucrul cu volume mari de date.

6.2. Operații fundamentale

Cele 4 operații de bază:

  1. Deschidere — stabilirea legăturii cu fișierul.
  2. Citire / Scriere — transferul de date.
  3. Închidere — eliberarea resurselor.

6.3. Lucrul cu fișiere în Python

Deschiderea unui fișier

f = open("date.txt", "r")    # citire (read)
f = open("date.txt", "w")    # scriere (write) — șterge conținutul
f = open("date.txt", "a")    # adăugare (append) la sfârșit
f = open("date.txt", "r+")   # citire + scriere

Citirea dintr-un fișier

# Citirea întregului conținut
f = open("date.txt", "r")
continut = f.read()
print(continut)
f.close()

# Citirea linie cu linie
f = open("date.txt", "r")
for linie in f:
    print(linie.strip())  # strip() elimină \n de la sfârșit
f.close()

# Citirea tuturor liniilor într-o listă
f = open("date.txt", "r")
linii = f.readlines()
f.close()

Scrierea într-un fișier

f = open("iesire.txt", "w")
f.write("Prima linie\n")
f.write("A doua linie\n")
f.close()

Gestionarea automată — with

Metoda recomandată: fișierul se închide automat.

with open("date.txt", "r") as f:
    continut = f.read()
# Aici fișierul este deja închis
print(continut)

6.4. Exemplu complet — numere dintr-un fișier

Fișierul numere.txt:

10 25 3
17 8 42
99 1 56

Program — calculează suma tuturor numerelor:

suma = 0
with open("numere.txt", "r") as f:
    for linie in f:
        for cuvant in linie.split():
            suma += int(cuvant)

print(f"Suma totală: {suma}")

# Scrierea rezultatului
with open("rezultat.txt", "w") as f:
    f.write(f"Suma este: {suma}\n")

6.5. Fișiere text în C++

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main() {
    // Scriere
    ofstream fout("iesire.txt");
    fout << "Prima linie\n";
    fout << "A doua linie\n";
    fout.close();

    // Citire — numere
    ifstream fin("numere.txt");
    int suma = 0, x;
    while (fin >> x) {
        suma += x;
    }
    fin.close();

    cout << "Suma: " << suma << endl;
    return 0;
}

6.6. Tratarea erorilor

Python:

try:
    with open("fisier_inexistent.txt", "r") as f:
        continut = f.read()
except FileNotFoundError:
    print("Fișierul nu există!")
except PermissionError:
    print("Nu ai permisiuni!")

C++:

ifstream fin("fisier.txt");
if (!fin.is_open()) {
    cerr << "Nu pot deschide fișierul!" << endl;
    return 1;
}

6.7. Problemă rezolvată — statistici din fișier

Citim numere dintr-un fișier și calculăm min, max, media, numărul de elemente.

def statistici(nume_fisier):
    cu open(nume_fisier, "r") as f:  # atenție: citim numere separate prin spații
        continut = f.read()

    numere = [int(x) for x in continut.split()]

    if not numere:
        print("Fișier gol!")
        return

    print(f"Elemente: {len(numere)}")
    print(f"Minim: {min(numere)}")
    print(f"Maxim: {max(numere)}")
    print(f"Sumă: {sum(numere)}")
    print(f"Medie: {sum(numere)/len(numere):.2f}")

statistici("numere.txt")

✏️ Exerciții propuse — Capitolul 6

  1. Citește un text dintr-un fișier și numără câte cuvinte conține.
  2. Copiază conținutul unui fișier în altul, transformând literele mici în majuscule.
  3. Citește numere dintr-un fișier și scrie în alt fișier doar numerele prime.
  4. Citește un fișier și afișează primele 5 linii.

Capitolul 7: Modelul conceptual liniar — lista

7.1. Ce este o listă?

O listă este o colecție de elemente dispuse liniar, în care:

  • Fiecare element (cu excepția primului și ultimului) are un predecesor și un succesor.
  • Ordinea contează.
  • Putem avea elemente duplicate.

Exemple din realitate:

  • Pasagerii într-un autobuz (dispuși pe rânduri).
  • Cărțile pe un raft (de la stânga la dreapta).
  • Notele unui elev în catalog (în ordinea introducerii).

7.2. Tipuri de liste după tipul de acces

a) Listă cu acces direct (indexată)

Putem accesa orice element direct, cunoscându-i poziția (index).

Exemplu: Catalogul clasei — putem vedea direct al 5-lea elev fără a parcurge primii 4.

clasa = ["Ana", "Bogdan", "Cristina", "Daniel", "Elena"]
print(clasa[4])  # "Elena" — accesul direct

b) Listă cu acces secvențial

Pentru a accesa un element, trebuie să parcurgem elementele de dinaintea lui.

Exemplu: Trenul pe șine — pentru a ajunge la vagonul 5, trebuie să treci prin 1, 2, 3, 4.

7.3. Stiva (Stack) — LIFO

LIFO = Last In, First Out (ultimul intrat, primul ieșit).

Analogie: Stiva de farfurii. Pui farfurii una peste alta. Când vrei să iei una, o iei pe cea de deasupra (ultima pusă).

Operații principale:

  • push(x) — adaugă x la vârf.
  • pop() — elimină și returnează vârful.
  • top() — vede vârful fără a-l elimina.

Aplicații:

  • Funcția „Undo” (anulare ultimă acțiune).
  • Evaluarea expresiilor matematice.
  • Stivă de apeluri de funcții (call stack).

Implementare în Python

stiva = []

# Push
stiva.append(10)
stiva.append(20)
stiva.append(30)
print(stiva)  # [10, 20, 30]

# Pop
x = stiva.pop()
print(x)      # 30
print(stiva)  # [10, 20]

# Top
print(stiva[-1])  # 20 (fără a elimina)

Implementare în C++

#include <stack>
using namespace std;

stack<int> s;
s.push(10);
s.push(20);
s.push(30);

cout << s.top();  // 30
s.pop();
cout << s.top();  // 20

7.4. Coada (Queue) — FIFO

FIFO = First In, First Out (primul intrat, primul ieșit).

Analogie: Coada la magazin. Primul care intră în rând este primul servit.

Operații:

  • enqueue(x) — adaugă la coada listei.
  • dequeue() — elimină de la capul listei.

Aplicații:

  • Imprimantele (documentele imprimă în ordinea trimiterii).
  • Simularea cozilor din realitate.
  • Procesarea evenimentelor.

Implementare în Python

coada = []

# Enqueue (adăugare la final)
coada.append("Ion")
coada.append("Maria")
coada.append("Alex")

# Dequeue (eliminare de la început)
primul = coada.pop(0)
print(primul)  # "Ion"
print(coada)   # ["Maria", "Alex"]

Implementare în C++

#include <queue>
using namespace std;

queue<int> q;
q.push(10);
q.push(20);
q.push(30);

cout << q.front();  // 10
q.pop();
cout << q.front();  // 20

7.5. Comparație stivă vs. coadă

Criteriu Stivă Coadă
Regulă LIFO FIFO
Adăugare La vârf La coadă
Eliminare De la vârf De la cap
Analogie Farfurii stivuite Rând la casă
Aplicație tipică Undo Imprimantă

7.6. Lista de frecvențe

O listă de frecvențe f pentru un set de valori este o listă în care f[i] reprezintă de câte ori apare valoarea i.

Exemplu: Într-un sondaj, avem notele (de la 1 la 5 stele):
[5, 3, 4, 5, 2, 5, 3, 5, 4, 1]

Lista de frecvențe este:

  • f[1] = 1 (1 stea apare 1 dată)
  • f[2] = 1 (2 stele apar 1 dată)
  • f[3] = 2 (3 stele apar 2 ori)
  • f[4] = 2 (4 stele apar 2 ori)
  • f[5] = 4 (5 stele apar 4 ori)

Construcția listei de frecvențe

note = [5, 3, 4, 5, 2, 5, 3, 5, 4, 1]
frecvente = [0] * 6  # index 0..5

for nota in note:
    frecvente[nota] += 1

for i in range(1, 6):
    print(f"Nota {i}: {frecvente[i]} apariții")
int note[] = {5, 3, 4, 5, 2, 5, 3, 5, 4, 1};
int n = 10;
int frecvente[6] = {0};  // inițializat cu 0

for (int i = 0; i < n; i++)
    frecvente[note[i]]++;

for (int i = 1; i <= 5; i++)
    cout << "Nota " << i << ": " << frecvente[i] << endl;

Aplicații ale listei de frecvențe:

  • Sortarea (vom vedea în Capitolul 10).
  • Găsirea elementului cel mai frecvent (modulul).
  • Statistici (histogramă).

7.7. Parcurgerea liniară

Parcurgere fără memorare — procesăm elementul curent fără a reține rezultate intermediare.

Problemă: Numără câți elevi au notă peste 7.

note = [9, 6, 8, 5, 10, 4, 7, 9, 8]
contor = 0
for n in note:
    if n > 7:
        contor += 1
print(contor)  # 5

Parcurgere cu memorare — reținem informațiile relevante într-o altă structură.

Problemă: Găsește toți elevii cu notă peste medie.

note = [9, 6, 8, 5, 10, 4, 7, 9, 8]
media = sum(note) / len(note)  # 7.33

peste_medie = []
for n in note:
    if n > media:
        peste_medie.append(n)

print(peste_medie)  # [9, 8, 10, 9, 8]

7.8. Repere pentru parcurgere

Pentru a identifica perechi de elemente consecutive:

lista = [1, 2, 3, 4, 5]
# Parcurgem de la index 0 la len-2
for i in range(len(lista) - 1):
    a = lista[i]
    b = lista[i + 1]
    print(f"({a}, {b})")
# (1,2) (2,3) (3,4) (4,5)

✏️ Exerciții propuse — Capitolul 7

  1. Implementează o stivă folosind doar o listă și scrie funcții push, pop, top.
  2. Folosind o stivă, inversează o listă.
  3. Construiește histogramul (lista de frecvențe) pentru literele unui cuvânt.
  4. Într-un magazin, simulează o coadă de clienți care intră și sunt serviți.

Capitolul 8: Clasa list din Python și vectori în C++

8.1. Clasa list — caracteristici

Clasa list din Python este predefinită și are următoarele caracteristici:

  • Mutabilă — poate fi modificată după creare.
  • Ordonată — elementele păstrează ordinea de inserare.
  • Indexată — acces prin poziție (0, 1, 2, …).
  • Eterogenă — poate conține tipuri diferite de date.
  • Dimensiune dinamică — crește/scade automat.

8.2. Crearea listelor în Python

# Listă vidă
lista1 = []
lista2 = list()

# Listă cu valori inițiale
numere = [1, 2, 3, 4, 5]
nume = ["Ana", "Bogdan", "Cristina"]
mix = [1, "text", 3.14, True]

# Listă generată
patrate = [x*x for x in range(10)]   # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
zerouri = [0] * 10                    # [0,0,0,0,0,0,0,0,0,0]

# Din input
n = int(input("Câte numere: "))
numere = []
for i in range(n):
    x = int(input(f"a[{i}] = "))
    numere.append(x)

# Sau mai compact:
numere = [int(x) for x in input().split()]  # "1 2 3 4" → [1, 2, 3, 4]

8.3. Acces la elemente

a = [10, 20, 30, 40, 50]

# Indexare directă (de la 0)
print(a[0])    # 10
print(a[4])    # 50

# Indexare negativă (de la sfârșit)
print(a[-1])   # 50
print(a[-2])   # 40

# Slicing
print(a[1:4])  # [20, 30, 40] — de la index 1 la 3 inclusiv
print(a[:3])   # [10, 20, 30] — primele 3
print(a[2:])   # [30, 40, 50] — de la index 2 la final
print(a[::2])  # [10, 30, 50] — din 2 în 2
print(a[::-1]) # [50, 40, 30, 20, 10] — inversat

8.4. Operatori specifici

Operator Descriere Exemplu
[] Acces la element a[0]
+ Concatenare [1,2] + [3,4] = [1,2,3,4]
* Multiplicare [0]*3 = [0,0,0]
in Apartenență 3 in [1,2,3] → True
not in Non-apartenență 5 not in [1,2,3] → True
== Egalitate [1,2] == [1,2] → True
<, >, <=, >= Comparație lexicografică [1,2] < [1,3] → True
a = [1, 2, 3]
b = [4, 5]

c = a + b       # [1, 2, 3, 4, 5]
d = a * 3       # [1, 2, 3, 1, 2, 3, 1, 2, 3]

print(2 in a)           # True
print(10 not in a)      # True
print([1, 2] == [1, 2]) # True

8.5. Metode ale clasei list

Adăugare

a = [1, 2, 3]

a.append(4)        # [1, 2, 3, 4] — la final
a.insert(0, 10)    # [10, 1, 2, 3, 4] — la poziția 0
a.extend([5, 6])   # [10, 1, 2, 3, 4, 5, 6] — extinde cu altă listă

Eliminare

a = [1, 2, 3, 2, 4]

a.remove(2)   # [1, 3, 2, 4] — elimină PRIMA apariție a lui 2
x = a.pop()   # x = 4, a = [1, 3, 2]
y = a.pop(0)  # y = 1, a = [3, 2]
a.clear()     # a = []

Căutare și numărare

a = [1, 2, 3, 2, 4, 2]

print(a.count(2))  # 3 — de câte ori apare 2
print(a.index(3))  # 2 — poziția primei apariții a lui 3
# a.index(100)     # eroare — nu este în listă

Ordonare și manipulare

a = [3, 1, 4, 1, 5, 9, 2, 6]

a.sort()           # [1, 1, 2, 3, 4, 5, 6, 9] — modifică lista
a.sort(reverse=True) # [9, 6, 5, 4, 3, 2, 1, 1]
a.reverse()        # inversează ordinea

b = sorted(a)      # creează o listă NOUĂ sortată, nu modifică `a`

Copiere

# ATENȚIE: atribuirea directă NU face copie!
a = [1, 2, 3]
b = a           # b și a se referă la ACEEAȘI listă
b.append(99)
print(a)        # [1, 2, 3, 99] — modificat!

# Copie superficială
a = [1, 2, 3]
b = a.copy()    # sau b = a[:] sau b = list(a)
b.append(99)
print(a)        # [1, 2, 3] — neschimbat
print(b)        # [1, 2, 3, 99]

8.6. Tabel sintetic — metode list

Metodă Acțiune Modifică lista?
append(x) Adaugă x la final Da
insert(i, x) Inserează x la poziția i Da
extend(lst) Extinde cu elementele din lst Da
remove(x) Elimină prima apariție a lui x Da
pop([i]) Elimină și returnează elementul de la poziția i (default: ultimul) Da
clear() Elimină toate elementele Da
count(x) Returnează numărul de apariții ale lui x Nu
index(x) Returnează poziția primei apariții a lui x Nu
sort() Sortează crescător Da
reverse() Inversează ordinea Da
copy() Returnează o copie superficială Nu

8.7. Parcurgerea unei liste

a = [10, 20, 30, 40, 50]

# Prin valoare
for x in a:
    print(x)

# Prin index
for i in range(len(a)):
    print(f"a[{i}] = {a[i]}")

# Prin index și valoare (elegant)
for i, x in enumerate(a):
    print(f"a[{i}] = {x}")

8.8. Vectori în C++

În C++ avem două opțiuni principale:

a) Tablou static

int a[100];  // tablou de 100 de elemente int
int n;
cin >> n;
for (int i = 0; i < n; i++)
    cin >> a[i];

// Afișare
for (int i = 0; i < n; i++)
    cout << a[i] << " ";

b) std::vector (recomandat — echivalent cu list din Python)

#include <vector>
#include <algorithm>
using namespace std;

vector<int> a;       // vector vid
vector<int> b(10);   // 10 elemente inițializate cu 0
vector<int> c(10, 5);// 10 elemente inițializate cu 5
vector<int> d = {1, 2, 3, 4, 5};

// Adăugare
a.push_back(10);
a.push_back(20);
a.insert(a.begin(), 0);  // inserare la început

// Acces
cout << a[0] << endl;
cout << a.front() << endl;  // primul
cout << a.back() << endl;   // ultimul
cout << a.size() << endl;   // dimensiune

// Eliminare
a.pop_back();     // ultimul element
a.erase(a.begin() + 1);  // elementul de la poziția 1
a.clear();        // toate

// Sortare
sort(d.begin(), d.end());

// Parcurgere
for (int x : d)
    cout << x << " ";

for (int i = 0; i < d.size(); i++)
    cout << d[i] << " ";

8.9. Probleme rezolvate

Problema 1 — Numărul de apariții ale unei valori

def numar_aparitii(lista, valoare):
    contor = 0
    for x in lista:
        if x == valoare:
            contor += 1
    return contor

# Echivalent cu: lista.count(valoare)
print(numar_aparitii([1, 2, 3, 2, 4, 2], 2))  # 3

Problema 2 — Elementele unice dintr-o listă

def elemente_unice(lista):
    unice = []
    for x in lista:
        if x not in unice:
            unice.append(x)
    return unice

print(elemente_unice([1, 2, 3, 2, 4, 3, 5]))  # [1, 2, 3, 4, 5]

Problema 3 — Găsirea perechilor consecutive cu aceeași paritate

def perechi_par_par(lista):
    contor = 0
    for i in range(len(lista) - 1):
        if lista[i] % 2 == 0 and lista[i+1] % 2 == 0:
            contor += 1
    return contor

print(perechi_par_par([2, 4, 3, 6, 8, 1]))  # 2: (2,4) și (6,8)

✏️ Exerciții propuse — Capitolul 8

  1. Citește n numere într-o listă și afișează-le în ordine inversă (fără reverse()).
  2. Calculează suma elementelor de pe pozițiile pare.
  3. Găsește al doilea element ca valoare (al doilea maxim).
  4. Șterge duplicatele dintr-o listă, păstrând ordinea.
  5. Rotește o listă la stânga cu k poziții.

Capitolul 9: Generarea sistematică a elementelor unei liste

9.1. Ce înseamnă generare sistematică?

Generarea sistematică = construirea unei liste în care elementele respectă o regulă clară, pas cu pas.

Tipuri de reguli:

  • Formulă explicită: a[i] = f(i) (ex: a[i] = i²)
  • Recurență: a[i] = f(a[i-1], a[i-2], ...) (ex: Fibonacci)
  • Condiție: toate numerele până la n care respectă o proprietate.

9.2. Generare cu formulă explicită

Exemplu 1 — primele n pătrate perfecte

def patrate(n):
    return [i*i for i in range(1, n+1)]

print(patrate(5))  # [1, 4, 9, 16, 25]

Exemplu 2 — primele n puteri ale lui 2

def puteri_doi(n):
    return [2**i for i in range(n)]

print(puteri_doi(10))  # [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]

9.3. Generare recurentă

Șir recurent: fiecare termen se calculează pe baza unor termeni anteriori.

Formula generală

a[0], a[1], ... — termeni inițiali (dați)
a[n] = f(a[n-1], a[n-2], ...) — relația de recurență

9.4. Șirul lui Fibonacci

Definiție:

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

Implementare iterativă (eficientă, O(n))

def fibonacci(n):
    """Returnează o listă cu primii n termeni Fibonacci."""
    if n == 0:
        return []
    if n == 1:
        return [0]

    fib = [0, 1]
    for i in range(2, n):
        fib.append(fib[i-1] + fib[i-2])
    return fib

print(fibonacci(10))  # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
#include <vector>
vector<int> fibonacci(int n) {
    vector<int> fib;
    if (n == 0) return fib;
    fib.push_back(0);
    if (n == 1) return fib;
    fib.push_back(1);
    for (int i = 2; i < n; i++)
        fib.push_back(fib[i-1] + fib[i-2]);
    return fib;
}

Implementare recursivă (elegantă dar INEFICIENTĂ — O(2ⁿ))

def fib_rec(n):
    if n < 2:
        return n
    return fib_rec(n-1) + fib_rec(n-2)

print(fib_rec(10))  # 55
# print(fib_rec(50))  # foarte lent!

Lecție: Recursivitatea este elegantă, dar fără memorare poate duce la explozii exponențiale de timp.

9.5. Proporția de aur (φ)

Raportul a doi termeni consecutivi Fibonacci tinde la φ ≈ 1.618, numit numărul de aur.

fib = fibonacci(20)
for i in range(2, 20):
    print(f"F({i})/F({i-1}) = {fib[i]/fib[i-1]:.6f}")
# Se apropie de 1.618034...

Aplicații ale proporției de aur:

  • Arhitectură (Parthenonul).
  • Artă (pictura renascentistă).
  • Natură (spiralele cochiliilor, aranjarea semințelor de floarea-soarelui).

9.6. Problemă practică — investiție bancară

Problemă: Ai S lei depuși cu dobânda d% anual. După câți ani suma depășește T?

def ani_pentru_suma(S, d, T):
    ani = 0
    suma = S
    while suma <= T:
        suma = suma * (1 + d/100)
        ani += 1
    return ani, suma

ani, suma_finala = ani_pentru_suma(1000, 5, 2000)
print(f"După {ani} ani: {suma_finala:.2f}")  # ~15 ani

9.7. Alte secvențe recurente clasice

Factorialul

n! = 1 * 2 * 3 * ... * n
0! = 1 (convenție)

Recurență: n! = n * (n-1)!

def factoriale(n):
    fact = [1]  # 0! = 1
    for i in range(1, n+1):
        fact.append(fact[i-1] * i)
    return fact

print(factoriale(5))  # [1, 1, 2, 6, 24, 120]

Șirul triunghiular

T(n) = 1 + 2 + 3 + ... + n = n*(n+1)/2
def triunghiulare(n):
    t = [0]
    for i in range(1, n+1):
        t.append(t[i-1] + i)
    return t

print(triunghiulare(5))  # [0, 1, 3, 6, 10, 15]

9.8. Generare cu condiție

Problemă: Generează toate numerele naturale până la n care sunt divizibile cu 3 și 5.

def divizibile(n):
    return [x for x in range(1, n+1) if x % 3 == 0 and x % 5 == 0]

print(divizibile(50))  # [15, 30, 45]

Problemă: Generează toate pătratele perfecte ≤ n.

def patrate_pana_la(n):
    rezultat = []
    i = 1
    while i*i <= n:
        rezultat.append(i*i)
        i += 1
    return rezultat

print(patrate_pana_la(100))  # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

✏️ Exerciții propuse — Capitolul 9

  1. Generează primii n termeni ai șirului a[i] = 2*a[i-1] + 1, cu a[0] = 1.
  2. Generează lista [3, 6, 9, 12, ...] până la n.
  3. Șirul Lucas: L[0]=2, L[1]=1, L[n]=L[n-1]+L[n-2]. Generează primii 15 termeni.
  4. Generează primele n numere prime.
  5. Temperaturile dintr-un oraș cresc în medie cu 1.2% pe an. Știind temperatura inițială, determină în câți ani va depăși o valoare dată.

Capitolul 10: Metode de sortare

10.1. Ce este sortarea?

Sortarea = rearanjarea elementelor unei liste într-o ordine specificată (crescătoare sau descrescătoare).

Exemple din realitate:

  • Aranjarea cărților în bibliotecă după nume.
  • Ordonarea elevilor după medie.
  • Aranjarea cărților de joc în mână.

10.2. Sortare prin selecția minimului (Selection Sort)

Idee

La fiecare pas, găsim cel mai mic element din partea nesortată și îl mutăm la începutul acesteia.

Algoritm

Pentru i de la 0 la n-2:
    Găsim poziția minimului din a[i..n-1], să zicem poz_min.
    Interschimbăm a[i] cu a[poz_min].

Vizualizare

Inițial:  [5, 3, 8, 1, 9]
                ↓ minim: 1 la poz 3
Pas 1:    [1, 3, 8, 5, 9]   (schimbăm 5 și 1)
                ↓ minim din [3,8,5,9]: 3 la poz 1 (deja acolo)
Pas 2:    [1, 3, 8, 5, 9]
                ↓ minim din [8,5,9]: 5 la poz 3
Pas 3:    [1, 3, 5, 8, 9]   (schimbăm 8 și 5)
                ↓ minim din [8,9]: 8
Pas 4:    [1, 3, 5, 8, 9]   (gata)

Implementare Python

def selection_sort(a):
    n = len(a)
    for i in range(n - 1):
        poz_min = i
        for j in range(i + 1, n):
            if a[j] < a[poz_min]:
                poz_min = j
        # Interschimbare
        a[i], a[poz_min] = a[poz_min], a[i]
    return a

print(selection_sort([5, 3, 8, 1, 9]))  # [1, 3, 5, 8, 9]

Implementare C++

void selection_sort(vector<int>& a) {
    int n = a.size();
    for (int i = 0; i < n - 1; i++) {
        int poz_min = i;
        for (int j = i + 1; j < n; j++)
            if (a[j] < a[poz_min])
                poz_min = j;
        swap(a[i], a[poz_min]);
    }
}

Complexitate

  • Comparări: (n-1) + (n-2) + ... + 1 = n(n-1)/2O(n²)
  • Interschimbări: maxim n-1O(n)
  • Funcționează la fel indiferent de distribuția datelor (favorabil = defavorabil).

10.3. Sortarea cu listă de frecvențe (Counting Sort)

Idee

Dacă valorile sunt întregi într-un interval mic [0..k], putem număra aparițiile fiecărei valori și reconstitui lista sortată.

Algoritm

1. Construim lista de frecvențe f[0..k].
2. Parcurgem f de la 0 la k:
     Scriem valoarea i de f[i] ori în lista rezultat.

Vizualizare

Inițial:   [3, 1, 2, 3, 1, 2, 3]
Frecvențe: f[1]=2, f[2]=2, f[3]=3
Rezultat:  [1, 1, 2, 2, 3, 3, 3]

Implementare Python

def counting_sort(a, val_max):
    frecvente = [0] * (val_max + 1)
    for x in a:
        frecvente[x] += 1

    rezultat = []
    for i in range(val_max + 1):
        for _ in range(frecvente[i]):
            rezultat.append(i)
    return rezultat

# Pentru note între 1 și 10
note = [7, 10, 5, 9, 7, 10, 6, 8, 9, 10]
print(counting_sort(note, 10))  # [5, 6, 7, 7, 8, 9, 9, 10, 10, 10]

Implementare C++

void counting_sort(vector<int>& a, int val_max) {
    vector<int> f(val_max + 1, 0);
    for (int x : a) f[x]++;

    int idx = 0;
    for (int i = 0; i <= val_max; i++)
        while (f[i]-- > 0)
            a[idx++] = i;
}

Complexitate

  • Timp: O(n + k), unde k = valoarea maximă.
  • Spațiu: O(k) pentru lista de frecvențe.

Avantaj: Foarte rapid dacă valorile sunt într-un interval mic.
Dezavantaj: Ineficient dacă k este foarte mare comparativ cu n.

Când să folosești: triaj de pacienți (valori 1-5), note școlare (1-10), categorii de produse.

10.4. Metoda bulelor (Bubble Sort)

Idee

Parcurgem lista în mod repetat, comparând elementele adiacente. Dacă sunt în ordine greșită, le interschimbăm. Procesul se repetă până când lista este sortată.

Vizualizare

Inițial: [5, 3, 8, 1, 9]

Pas 1:   [3, 5, 8, 1, 9]  (schimb 5 și 3)
         [3, 5, 8, 1, 9]  (5 < 8, nu se schimbă)
         [3, 5, 1, 8, 9]  (schimb 8 și 1)
         [3, 5, 1, 8, 9]  (8 < 9, nu se schimbă)

Pas 2:   [3, 5, 1, 8, 9]
         [3, 1, 5, 8, 9]  (schimb 5 și 1)
         ...

Continuă până nu mai sunt schimbări.

Implementare Python — varianta de bază

def bubble_sort(a):
    n = len(a)
    for i in range(n):
        for j in range(n - i - 1):
            if a[j] > a[j+1]:
                a[j], a[j+1] = a[j+1], a[j]
    return a

print(bubble_sort([5, 3, 8, 1, 9]))  # [1, 3, 5, 8, 9]

Implementare optimizată (oprire dacă nu s-au făcut schimbări)

def bubble_sort_opt(a):
    n = len(a)
    for i in range(n):
        schimbat = False
        for j in range(n - i - 1):
            if a[j] > a[j+1]:
                a[j], a[j+1] = a[j+1], a[j]
                schimbat = True
        if not schimbat:
            break  # lista este deja sortată
    return a

Implementare C++

void bubble_sort(vector<int>& a) {
    int n = a.size();
    for (int i = 0; i < n; i++) {
        bool schimbat = false;
        for (int j = 0; j < n - i - 1; j++) {
            if (a[j] > a[j+1]) {
                swap(a[j], a[j+1]);
                schimbat = true;
            }
        }
        if (!schimbat) break;
    }
}

Complexitate

  • Caz favorabil (deja sortat, cu optimizare): O(n)
  • Caz mediu și defavorabil: O(n²)

10.5. Comparație între metode

Metodă Timp (mediu) Timp (cel mai rău) Memorie adițională Stabilă?
Selecția minimului O(n²) O(n²) O(1) Nu
Listă de frecvențe O(n+k) O(n+k) O(k) Da
Metoda bulelor O(n²) O(n²) O(1) Da

Când să folosești fiecare:

  • Selecția minimului: când interschimbările sunt costisitoare (garantează minim de schimbări).
  • Listă de frecvențe: când valorile sunt în interval mic și avem multe elemente.
  • Metoda bulelor: educațional; în practică se preferă alte metode.

💡 Notă: În practică, pentru sortări generale se folosesc algoritmi mai eficienți precum QuickSort sau MergeSort (O(n log n)). Python folosește intern TimSort. Pentru clasa a IX-a, metodele prezentate sunt suficiente.

10.6. Probleme rezolvate

Problema 1 — Primele k elemente mai mari

Din [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5], afișează cele mai mari 3 valori.

def top_k_mari(lista, k):
    # Sortăm descrescător și luăm primele k
    sortata = sorted(lista, reverse=True)
    return sortata[:k]

print(top_k_mari([3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5], 3))  # [9, 6, 5]

Problema 2 — Triaj de pacienți

Într-o urgență, pacienții au coduri de gravitate 1-5 (5 fiind cel mai grav). Ordonează-i descrescător pentru a-i servi.

def triaj(pacienti):
    """Folosim counting sort pentru că avem interval mic."""
    frecvente = [0] * 6  # 0..5
    for cod in pacienti:
        frecvente[cod] += 1

    rezultat = []
    # Descrescător — de la 5 la 1
    for i in range(5, 0, -1):
        for _ in range(frecvente[i]):
            rezultat.append(i)
    return rezultat

pacienti = [3, 1, 5, 2, 5, 4, 3, 1, 5]
print(triaj(pacienti))  # [5, 5, 5, 4, 3, 3, 2, 1, 1]

Problema 3 — Sortarea după două criterii

Elevi cu nume și notă. Sortare după notă descrescător, apoi alfabetic la egalitate.

elevi = [
    ("Ana", 9),
    ("Bogdan", 10),
    ("Cristina", 9),
    ("Daniel", 8)
]

# key = funcție care spune după ce sortăm
# -x[1] = sortare descrescătoare după notă
# x[0]  = sortare alfabetică după nume
elevi_sortati = sorted(elevi, key=lambda x: (-x[1], x[0]))
print(elevi_sortati)
# [('Bogdan', 10), ('Ana', 9), ('Cristina', 9), ('Daniel', 8)]

✏️ Exerciții propuse — Capitolul 10

  1. Implementează selection sort care sortează descrescător.
  2. Sortează o listă de cuvinte în ordine alfabetică folosind metoda bulelor.
  3. Folosind counting sort, sortează literele dintr-un cuvânt.
  4. Sortează o listă de perechi (nume, vârstă) după vârstă.
  5. Numără câte interschimbări face bubble sort pentru o listă dată.
  6. Găsește al k-lea cel mai mic element fără a sorta complet lista.

Anexe

Anexa A — Recapitulare: Python vs. C++ — cheat sheet

Concept Python C++
Comentariu # comentariu // comentariu sau /* ... */
Importuri import math #include <cmath>
Punct de intrare codul direct int main() { ... }
Afișare print(x) cout << x
Citire x = input() cin >> x
Delimitator bloc indentare { ... }
Definire funcție def f(x): int f(int x) { ... }
Lista lista = [1, 2, 3] vector<int> v = {1, 2, 3}
Lungime len(lista) v.size()
Adaugă lista.append(x) v.push_back(x)
Sortare lista.sort() sort(v.begin(), v.end())
String s = "text" string s = "text"

Anexa B — Probleme de proiect (pentru lucrul în echipă)

  1. Gestionar de note — aplicație GUI cu Tkinter care stochează notele într-un fișier text.
  2. Calculator științific — aplicație cu butoane pentru operații matematice.
  3. Simulare de bursă — ține evidența prețurilor unor acțiuni, calculează statistici.
  4. Quiz de matematică — aplicație care generează probleme, verifică răspunsurile, păstrează scoruri.
  5. Agenda personală — adaugă, căutare, ștergere de contacte într-un fișier.
  6. Analiză de text — număr de cuvinte, histogramă de litere, cuvinte frecvente.
  7. Joc „Ghici numărul” — cu interfață grafică și scor păstrat în fișier.

Anexa C — Resurse utile online

Vizualizări interactive

Platforme de exerciții

Documentație

Anexa D — Glosar de termeni

Termen Definiție
Algoritm Succesiune finită și precisă de pași pentru rezolvarea unei probleme.
Variabilă Locație de memorie cu un nume, ce stochează o valoare.
Listă / Vector / Tablou Colecție ordonată de elemente accesibile prin index.
Index Poziția unui element într-o listă (începe de la 0 în Python și C++).
Subprogram / Funcție Secvență de cod nominalizată care execută o sarcină.
Parametru Variabilă folosită pentru a transmite date unei funcții.
Argument Valoarea concretă transmisă când apelăm o funcție.
Complexitate Măsura eficienței unui algoritm în funcție de dimensiunea intrării.
LIFO Last In, First Out — principiu de acces al stivei.
FIFO First In, First Out — principiu de acces al cozii.
Iterație O singură execuție a corpului unei bucle.
Recursivitate Tehnică prin care o funcție se apelează pe sine.
Modularizare Împărțirea unui program în module independente.
GUI Graphical User Interface — interfață grafică.
IDE Integrated Development Environment — mediu integrat de dezvoltare.

Anexa E — Pseudocodul programei — referință rapidă

// Citire/Scriere
citește a, b
scrie "Rezultat:", x

// Atribuire
x ← 5

// Decizie
dacă a > b atunci
   scrie a
altfel
   scrie b
sfârșit dacă

// Repetitivă cu test inițial
cât timp i <= n execută
   ...
sfârșit cât timp

// Repetitivă cu test final
repetă
   ...
până când condiție

// Repetitivă cu contor
pentru i ← 1, n execută
   ...
sfârșit pentru

// Subprogram
subprogram dublu(x) returnează întreg
   return 2 * x
sfârșit subprogram

apel dublu(5)

🎓 Încheiere

Ai parcurs integral materia de clasa a IX-a! Cursul a acoperit:

✅ Principiile elaborării programelor
✅ Prelucrări ale numerelor (CMMDC, divizori, baze)
✅ Subprograme și modularitate
✅ POO și clase predefinite
✅ Interfețe grafice (Tkinter)
✅ Fișiere text
✅ Modelul conceptual liniar (listă, stivă, coadă)
✅ Clasa list din Python / vector din C++
✅ Generarea sistematică (Fibonacci, secvențe recurente)
✅ Metode de sortare (selecție, frecvențe, bule)

Recomandări pentru continuare:

  1. Practică zilnică — rezolvă cel puțin o problemă pe zi pe pbinfo.ro.
  2. Proiecte personale — aplică ce ai învățat în proiecte care te pasionează (jocuri, aplicații utilitare).
  3. Contribuie — participă la cercuri de informatică, olimpiade locale.
  4. Aprofundează — explorează structuri mai complexe (dicționare, seturi) și biblioteci (NumPy, Pandas).
  5. Programează zilnic — fluența vine din repetiție.

„Programarea nu este despre a scrie cod — este despre a gândi.”


Document generat în conformitate cu Programa școlară pentru disciplina Informatică, clasa a IX-a, curriculum de specialitate, Ordin MEC 4.350/2025.

Pe această pagină