Matrici (Tablouri Bidimensionale)

Noțiuni de bază

Declarare, citire, afișare și parcurgeri elementare pe matrici.

Declarare, inițializare și accesul la elemente

O matrice este un tablou bidimensional -- un tabel cu linii si coloane. In C++ o declaram cu doua dimensiuni.

Declarare

int m[100][100];   // matrice de maxim 100 linii si 100 coloane

Dimensiunile se aleg in functie de enunt. Daca enuntul spune "cel mult N linii si M coloane", declari m[N+1][M+1] sau direct cu o valoare sigura ca 100 sau 1001.

Liniile si coloanele se numeroteaza de obicei de la 1 la BAC, deci declari cu un rand/coloana in plus si ignori indicele 0.

int m[101][101];   // linii 1..100, coloane 1..100
int n, p;          // n = nr linii, p = nr coloane

Accesul la un element

m[i][j] este elementul de pe linia i, coloana j.

m[1][1] = 5;       // primul element (linia 1, coloana 1)
m[i][j] = 0;       // elementul de pe linia i, coloana j
cout << m[2][3];   // afiseaza elementul de pe linia 2, coloana 3

Matrice patratica

O matrice cu n linii si n coloane se numeste patratica. La BAC apar frecvent matrici patratice -- diagonalele, zonele si simetria se definesc pe ele.

int n;
int m[101][101];   // matrice patratica n x n

Initializare cu 0

int m[101][101] = {0};   // toate elementele 0 la declarare

Sau in timpul executiei:

for (int i = 1; i <= n; i++)
    for (int j = 1; j <= n; j++)
        m[i][j] = 0;

Citirea și afișarea unei matrici

Citire

Citim elementele linie cu linie, coloana cu coloana:

int n, p;
int m[101][101];

cin >> n >> p;   // n = nr linii, p = nr coloane
for (int i = 1; i <= n; i++)
    for (int j = 1; j <= p; j++)
        cin >> m[i][j];

Afisare

for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= p; j++) {
        cout << m[i][j];
        if (j < p) cout << " ";   // spatiu intre elemente, nu dupa ultimul
    }
    cout << endl;   // linie noua dupa fiecare rand
}

Sau mai simplu (cu spatiu si dupa ultimul element -- acceptat la BAC):

for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= p; j++)
        cout << m[i][j] << " ";
    cout << endl;
}

Matrice patratica -- citire si afisare

La matricea patratica avem un singur n:

int n;
int m[101][101];

cin >> n;
for (int i = 1; i <= n; i++)
    for (int j = 1; j <= n; j++)
        cin >> m[i][j];

for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= n; j++)
        cout << m[i][j] << " ";
    cout << endl;
}

Ordinea for-urilor conteaza

Mereu: for linie, for coloana -- asa parcurgem rand cu rand, exact cum sunt stocate in memorie si cum sunt citite/afisate datele.

for (int i = 1; i <= n; i++)      // linie
    for (int j = 1; j <= p; j++)  // coloana
        // m[i][j]

Cum se misca i si j -- exemplu pentru n=3, p=4

Pornind cu i=1, j=1, j avanseaza pana la capat, apoi i creste si j se reintoarce la 1:

j=1    j=2    j=3    j=4
i=1  m[1][1] m[1][2] m[1][3] m[1][4]   <- for-ul interior parcurge toata linia 1
i=2  m[2][1] m[2][2] m[2][3] m[2][4]   <- apoi toata linia 2
i=3  m[3][1] m[3][2] m[3][3] m[3][4]   <- si toata linia 3

Ordinea exacta a vizitarii elementelor:

pas  1:  i=1, j=1  => m[1][1]
pas  2:  i=1, j=2  => m[1][2]
pas  3:  i=1, j=3  => m[1][3]
pas  4:  i=1, j=4  => m[1][4]  <- j a ajuns la capat, i creste
pas  5:  i=2, j=1  => m[2][1]  <- j reincepe de la 1
pas  6:  i=2, j=2  => m[2][2]
pas  7:  i=2, j=3  => m[2][3]
pas  8:  i=2, j=4  => m[2][4]  <- j a ajuns la capat, i creste
pas  9:  i=3, j=1  => m[3][1]  <- j reincepe de la 1
pas 10:  i=3, j=2  => m[3][2]
pas 11:  i=3, j=3  => m[3][3]
pas 12:  i=3, j=4  => m[3][4]  <- gata
Notă: Regula simpla: j se misca repede (loop interior), i se misca incet (loop exterior). Cand j termina un tur complet, i avanseaza cu 1 si j se reintoarce la inceput.

Ce se intampla daca inversezi for-urile?

Daca scrii for j exterior si for i interior, parcurgi coloana cu coloana in loc de linie cu linie:

j=1    j=2    j=3    j=4
i=1  m[1][1] m[1][2] m[1][3] m[1][4]
i=2  m[2][1] m[2][2] m[2][3] m[2][4]
i=3  m[3][1] m[3][2] m[3][3] m[3][4]

Ordinea cu j exterior:
m[1][1], m[2][1], m[3][1],   <- coloana 1
m[1][2], m[2][2], m[3][2],   <- coloana 2
m[1][3], m[2][3], m[3][3],   <- coloana 3
m[1][4], m[2][4], m[3][4]    <- coloana 4

La citire si afisare aceasta ordine este gresita -- datele se citesc linie cu linie din input, nu coloana cu coloana. La unele operatii (de ex. suma tuturor elementelor) ordinea nu conteaza, dar la citire/afisare conteaza intotdeauna.

Parcurgeri elementare: sumă, min, max, numărare

Suma tuturor elementelor

long long suma = 0;
for (int i = 1; i <= n; i++)
    for (int j = 1; j <= p; j++)
        suma += m[i][j];
cout << suma;

Minimul si maximul din matrice

int minim = m[1][1], maxim = m[1][1];
for (int i = 1; i <= n; i++)
    for (int j = 1; j <= p; j++) {
        if (m[i][j] < minim) minim = m[i][j];
        if (m[i][j] > maxim) maxim = m[i][j];
    }
cout << minim << " " << maxim;

Numararea elementelor cu o proprietate

int cnt = 0;
for (int i = 1; i <= n; i++)
    for (int j = 1; j <= p; j++)
        if (m[i][j] % 2 == 0)   // de exemplu, numara elementele pare
            cnt++;
cout << cnt;

Verificarea unei conditii pentru toate elementele

bool toate_pozitive = true;
for (int i = 1; i <= n; i++)
    for (int j = 1; j <= p; j++)
        if (m[i][j] <= 0) {
            toate_pozitive = false;
            break;
        }

if (toate_pozitive) cout << "DA";
else cout << "NU";
Notă: Dupa break iesi doar din for-ul interior. Daca vrei sa iesi din ambele for-uri, foloseste o variabila flag sau goto (dar la BAC e mai elegant cu flag).

Cautarea unui element

int val;
cin >> val;

bool gasit = false;
int lin_gasit, col_gasit;

for (int i = 1; i <= n && !gasit; i++)
    for (int j = 1; j <= p && !gasit; j++)
        if (m[i][j] == val) {
            gasit = true;
            lin_gasit = i;
            col_gasit = j;
        }

if (gasit) cout << "Gasit la linia " << lin_gasit << ", coloana " << col_gasit;
else cout << "Nu exista";