Matrici: un’implementazione parametrica in C++ Ugo de'Liguoro - Informatica 2 a.a. 03/04 Lez. 10
ADT delle matrici Matrice di ordine n m Ugo de'Liguoro - Informatica 2 a.a. 03/04 Lez. 10
ADT delle matrici Retrive(i, j, M) Post: ritorna aij in M AssignEntry(i, j, x, M) Post: assegna ad x l’entrata aij di M Assign(M1,M2) Pre: M1 ed M2 hanno lo stesso ordine Post: assegna ad M1 le entrate di M2 Add(M1, M2) Pre: M1 ed M2 hanno lo stesso ordine Post: ritorna la somma M1 + M2 Mult (M1, M2) Pre: M1 ha ordine n m, M2 ha ordine m p Post: ritorna il prodotto M1 M2 di dimensione n p Ugo de'Liguoro - Informatica 2 a.a. 03/04 Lez. 10
Una struttura dati n m Ugo de'Liguoro - Informatica 2 a.a. 03/04 Lez. 10
La classe Matrix template <class T> class Matrix { private: int row_dim, col_dim; T** element; public: inline Matrix (); // costruttore di default Matrix (int rdim, int cdim); // costruttore Matrix (int rdim, int cdim, T* initval); // costruttore con inzializzazione delle entrate Matrix (const Matrix<T>&); // costruttre di copia ~Matrix (); // distruttore // altri metodi }; Ugo de'Liguoro - Informatica 2 a.a. 03/04 Lez. 10
Matrici come vettori di righe/colonne La memoria è unidimensionale: le matrici (con due o più dimensioni) possono essere rappresentate come un vettore di righe (o di colonne) Ugo de'Liguoro - Informatica 2 a.a. 03/04 Lez. 10
Un costruttore della classe Matrix template <class T> Matrix<T>::Matrix (int rdim, int cdim, T* initval) // Pre: initval elenca le entrate per riga { row_dim = rdim; col_dim = cdim; element = new T* [row_dim]; for (int i = 0; i < rdim; i++) element[i] = new T [col_dim]; for (int j = 0; j < cdim; j++) element[i][j] = initval [cdim * i + j]; } Ugo de'Liguoro - Informatica 2 a.a. 03/04 Lez. 10
Costruttore di copia template <class T> Matrix<T>::Matrix (const Matrix<T>& m) { row_dim = m.row_dim; col_dim = m.col_dim; element = new T* [row_dim]; for (int i = 0; i < rdim; i++) element[i] = new T [col_dim]; for (int j = 0; j < cdim; j++) element[i][j] = m.element[i][j]; } Ugo de'Liguoro - Informatica 2 a.a. 03/04 Lez. 10
Le deallocazioni con delete sono simmetriche alle allocazioni con new Il distruttore template <class T> Matrix<T>::~Matrix () { for (int i = 0; i < row_dim; i++) delete [] element[i]; delete [] element; } Le deallocazioni con delete sono simmetriche alle allocazioni con new Ugo de'Liguoro - Informatica 2 a.a. 03/04 Lez. 10
Metodi “get”: sono const const assicura che il metodo non altera lo stato template <class T> class Matrix { public: // altri metodi inline int Row () const { return row_dim; } inline int Col () const { return col_dim; } T GetEntry (int i, int j) const; // ritorna this[i, j] dove i e j variano da 1 // a n (== row_dim) ed m (== col_dim) risp. }; T Matrix<T>::GetEntry (int i, int j) const { assert (1 <= i && i <= row_dim && 1 <= j && j <= col_dim); return element[i - 1][j - 1]; } Ugo de'Liguoro - Informatica 2 a.a. 03/04 Lez. 10
Sovraccarico degli operatori template <class T> Matrix<T>& Matrix<T>::operator= (const Matrix<T>& m) { for (int i = 0; i < row_dim; i++) delete [] element[i]; delete [] element; row_dim = m.row_dim; col_dim = m.col_dim; element = new T* [row_dim]; for (int i = 0; i < rdim; i++) element[i] = new T [col_dim]; for (int i = 0; i < row_dim; i++) for (int j = 0; j < col_dim; j++) element[i][j] = m.element[i][j]; return *this; } Deallocazione dello stato “vecchio” Allocazione del nuovo stato Ugo de'Liguoro - Informatica 2 a.a. 03/04 Lez. 10
La somma di due matrici template <class T> class Matrix { template <class S> friend Matrix<S> operator+ (const Matrix<S>& m1, const Matrix<S> m2); }; template <class S> Matrix<S> operator+ (const Matrix<S>& m1, const Matrix<S> m2) { assert (m1.Row() == m2.Row() && m1.Col() == m2.Col()); Matrix<S> R (m1.Row(), m1.Col()); for (int i = 0; i < m1.Row(); i++) for (int j = 0; j < m1.Col(); j++) R.element[i][j] = m1.element[i][j] + m2.element[i][j]; return R; } Ugo de'Liguoro - Informatica 2 a.a. 03/04 Lez. 10
La stampa di una matrice Template <class T> Matrix { // ... template <class S> friend ostream& operator<<(ostream& os, const Matrix<S>& m); // invia una stampa di this sullo stream os // (tipicamente cout) }; Ugo de'Liguoro - Informatica 2 a.a. 03/04 Lez. 10
La stampa di una matrice template <class T> ostream& operator<<(ostream& os, const Matrix<T>& m) { for (int i = 0; i < m.row_dim; i++) { for (int j = 0; j < m.col_dim; j++) os << ' ' << m.element[i][j]; os << endl; } return os; os è una sorta di buffer, in cui si accumula il flusso dell’informazione, per poi essere “trasmessa” con return os Ugo de'Liguoro - Informatica 2 a.a. 03/04 Lez. 10
La stampa di una matrice int main() { int init[6] = {1, 2, 3, 4, 5, 6}; Matrix<int> M (2, 3, init); cout << M; } L’effetto di questa istruzione è analogo alla stampa di un intero Ugo de'Liguoro - Informatica 2 a.a. 03/04 Lez. 10
Calcolo del determinante Se A è una matrice n n (con n 2) allora dove il cofattore cij è definito: Ugo de'Liguoro - Informatica 2 a.a. 03/04 Lez. 10
Calcolo del determinante template <class T> T Matrix<T>::Det () { assert(row_dim == col_dim && row_dim >= 2); if (row_dim == 2) return element[0][0]*element[1][1] - element[0][1]*element[1][0]; else { T det = Minor(1,1)*element[0][0]; for (int i = 1; i < row_dim; i++) det += Minor(i+1,1)*element[i][0]; return det; } Minor usa indici da 1 in poi; element da 0 in poi Ugo de'Liguoro - Informatica 2 a.a. 03/04 Lez. 10
Vediamo ora il dettaglio dell’istruzione pseudocodificata I minori template <class T> T Matrix<T>::Minor (int i, int j) { Matrix<T> A (row_dim-1, col_dim-1); copia in A le entrate di this, salvo la riga i e la colonna j if ((i+j) % 2 == 0) return A.Det(); else return - A.Det(); } Vediamo ora il dettaglio dell’istruzione pseudocodificata Ugo de'Liguoro - Informatica 2 a.a. 03/04 Lez. 10
I minori template <class T> T Matrix<T>::Minor (int i, int j) { Matrix<T> A (row_dim-1, col_dim-1); for (int h = 0; h < i-1; h++) { for (int k = 0; k < j-1; k++) A.element[h][k] = element[h][k]; for (int k = j; k < col_dim; k++) A.element[h][k-1] = element[h][k]; } … Ugo de'Liguoro - Informatica 2 a.a. 03/04 Lez. 10
I minori template <class T> T Matrix<T>::Minor (int i, int j) { … for (int h = i; h < row_dim; h++) { for (int k = 0; k < j-1; k++) A.element[h-1][k] = element[h][k]; for (int k = j; k < col_dim; k++) A.element[h-1][k-1] = element[h][k]; } if ((i+j) % 2 == 0) return A.Det(); else return - A.Det(); Ugo de'Liguoro - Informatica 2 a.a. 03/04 Lez. 10