// (c) 2003. Dinko Korunic 'kreator' // // This program is free software; you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // Prva laboratorijska vjezba iz APR: // // Implementirati razred Matrica koji omogu?ava jednostavnije rukovanje // objektima tipa dvodimenzionalne matrice. Razred mora imati barem // sljede?e elemente: // * protected podatke o dimenzijama matrice i pokaziva? na elemente // matrice koji su tipa double. Smje?taj sadr?aja matrice u memoriji // organizirati po izboru (npr. dvostruki pokaziva?), ali se memorija // mora zauzimati dinami?ki (nema predefiniranih maksimalnih dimenzija // matrice) // * public nadgra?eni konstruktor matrice koji zauzima memoriju ako su // zadane dimenzije matrice i destruktor koji memoriju osloba?a // * public operator pridru?ivanja te kopiraju?i konstruktor. // * public metodu koja ?ita matricu iz tekstualne datoteke u kojoj je // matrica smje?tena tako da jedan redak matrice odgovara jednom retku u // datoteci. Na osnovu broja elemenata u prvom retku odre?uje se broj // stupaca matrice, a redaka ima koliko ima i redaka u datoteci. Brojevi // u jednom retku mogu biti odvojeni razmakom ili tabulatorom. Vidi // primjer ulazne datoteke na kraju! // * public metodu koja ispisuje matricu u datoteku u istom formatu, te // metodu koja ispisuje matricu na ekran. // * public metode za postavljanje i dohvat jednog elementa matrice. Mo?e // biti implementirano i istom metodom, uz kori?tenje funkcije koja vra?a // referencu (vidi materijale uz auditorne vje?be!) // * public metode za zbrajanje, oduzimanje, mno?enje i transponiranje // matrica, te metode koje obavljaju C operatore "+=" i "-=". Preporu?a se // da budu implementirane kao nadgra?eni operatori. Dodati i operator // mno?enja matrice sa skalarom. // U glavnom programu je potrebno instancirati nekoliko objekata matrica, // u?itati vrijednosti iz datoteka i obaviti nekoliko ra?unskih operacija // te prikazati rezultate. #include #include #include #include // makroi za skipanje razlicitih delimitera.. #define SkipDelimiterNL(ifs) SkipChar(ifs, " \n") #define SkipDelimiters(ifs) SkipChar(ifs, " \t") typedef vector Double1D; // jednodimenzionalni STL vektor typedef vector Double2D; // dvodimenzionalni STL vektor // osnovna klasa class Matrica { protected: int redaka, stupaca; // podaci o podacima :-) Double2D podaci; // 2D STL vektor sa elementima public: Matrica(); // osnovni konstruktor ~Matrica(); // osnovni destruktor Matrica(const int, const int); // konstruktor sa dimenzijama Matrica(const Matrica &); // konstruktor sa kopiranjem double Dohvati(int, int); // dohvati element double Postavi(int, int, const double); // postavi element Matrica& operator= (const Matrica &); // nadogr. pridruzivanje Matrica operator+ (const Matrica &); // nadogr. zbrajanje Matrica operator- (const Matrica &); // nadogr. oduzimanje Matrica operator* (const Matrica &); // nadogr. mnozenje Matrica operator* (double); // nadogr. mnozenje skalarom Matrica& operator+= (const Matrica &); // nadogr. += Matrica& operator-= (const Matrica &); // nadogr. -= Matrica& Transponiraj(); // nadogradjeno transponiranje friend ostream& operator<< (ostream &, Matrica &); // nadogr. << friend istream& operator>> (istream &, Matrica &); // nadogr. >> }; // class Matrica // prazni konstruktor - treba nam samo za retke/stupce Matrica::Matrica() { redaka = stupaca = 0; } // Matrica::Matrica() // konstruktor za matricu iz matrice // ulaz: referenca na izvornu matricu // izlaz: nista Matrica::Matrica(const Matrica &izvor) { *this = izvor; } // Matrica::Matrica(const Matrica) // konstruktor za stvaranje nove matrice proizvoljnih dimenzija // ulaz: retci, stupci // izlaz: nista Matrica::Matrica(const int _redaka, const int _stupaca) : redaka(_redaka), stupaca(_stupaca) { Double2D tmp(redaka, stupaca); podaci = tmp; } // Matrica::Matrica(int, int) // standardni destruktor - prazan jer se vektori automatski ciste // ulaz: nista // izlaz: nista Matrica::~Matrica() { } // Matrica::~Matrica() // dohvacanje proizvoljnog elementa iz matrice // ulaz: stupac, redak // izlaz: dohvaceni element double Matrica::Dohvati(int stupac, int redak) { if (!(--stupac < stupaca)) throw "Dohvati: stupac izvan matrice"; if (!(--redak < redaka)) throw "Dohvati: redak izvan matrice"; return podaci[redak][stupac]; } // Matrica::Dohvati(int, int) // postavljanje proizvoljnog elementa u matrici // ulaz: stupac, redak, podatak // izlaz: postavljeni element double Matrica::Postavi(int stupac, int redak, const double podatak) { if (!(--stupac < stupaca)) throw "Postavi: stupac izvan matrice"; if (!(--redak < redaka)) throw "Postavi: redak izvan matrice"; return (podaci[redak][stupac] = podatak); } // Matrica::Postavi(int, int, double) // operator pridruzivanja // ulaz: referenca na matricu // izlaz: referenca na vlastiti objekt Matrica& Matrica::operator= (const Matrica &izvor) { stupaca = izvor.stupaca; redaka = izvor.redaka; // izjednacimo stupce/retke podaci = izvor.podaci; // i onda same podatke (nadogr. =) return *this; } // Matrica& operator= (const Matrica &) // operator zbrajanja // ulaz: referenca na matricu // izlaz: matrica (novi objekt) Matrica Matrica::operator+ (const Matrica &izvor) { if ((izvor.stupaca != stupaca) || (izvor.redaka != redaka)) throw "operator+: matrice nemaju iste dimenzije"; Matrica rezultat(*this); // koristimo nadogradjeno instanciranje int i, j; for (i = 0; i < redaka; ++i) for (j = 0; j < stupaca; ++j) rezultat.podaci[i][j] += izvor.podaci[i][j]; // i za sve elem. return rezultat; } // Matrica Matrica::operator+ (const Matrica &) // operator oduzimanja // ulaz: referenca na matricu // izlaz: matrica (novi objekt) Matrica Matrica::operator- (const Matrica &izvor) { if ((izvor.stupaca != stupaca) || (izvor.redaka != redaka)) throw "operator+: matrice nemaju iste dimenzije"; Matrica rezultat(*this); int i, j; for (i = 0; i < redaka; ++i) for (j = 0; j < stupaca; ++j) rezultat.podaci[i][j] -= izvor.podaci[i][j]; // za sve.. return rezultat; } // Matrica Matrica::operator- (const Matrica &) // operator mnozenja skalarom // ulaz: skalar // izlaz: matrica (novi objekt) Matrica Matrica::operator* (const double izvor) { Matrica rezultat(*this); int i, j; for (i = 0; i < redaka; ++i) for (j = 0; j < stupaca; ++j) rezultat.podaci[i][j] *= izvor; // za sve elemente return rezultat; } // Matrica Matrica::operator* (double) // operator mnozenja matricom // ulaz: referenca na matricu // izlaz: matrica (novi objekt) Matrica Matrica::operator* (const Matrica &izvor) { if (stupaca != izvor.redaka) throw "operator*: matrice nisu ulancane"; Matrica rezultat(redaka, izvor.stupaca); int i, j, k; for (i = 0; i < redaka; ++i) for (j = 0; j < izvor.stupaca; ++j) for (k = 0; k < stupaca; ++k) rezultat.podaci[i][j] += podaci[i][k] * izvor.podaci[k][j]; // prema formuli A[i][j] = Sum a[i][j]b[k][j], k=1..n return rezultat; } // Matrica Matrica::operator* (const Matrica &) // operator zbrajanja i izjednacenja // ulaz: referenca na matricu // izlaz: referenca na matricu Matrica& Matrica::operator+= (const Matrica &izvor) { return (*this = *this + izvor); // najjednostavnije } // Matrica& Matrica::operator+= (const Matrica &) // operator oduzimanja i izjednacenja // ulaz: referenca na matricu // izlaz: referenca na matricu Matrica& Matrica::operator-= (const Matrica &izvor) { return (*this = *this - izvor); // najjednostavnije } // Matrica& Matrica::operator-= (const Matrica &) // transponiranje matrice // ulaz: nista // izlaz: referenca na matricu Matrica& Matrica::Transponiraj() { Matrica rezultat(stupaca, redaka); int i, j; for (i = 0; i < redaka; ++i) for (j = 0; j < stupaca; ++j) rezultat.podaci[j][i] = podaci[i][j]; // napravimo novi objekt tocnih dimenzija // i napunimo ga podacima return (*this = rezultat); } // Matrica& Matrica::Transponiraj() // preskacemo zeljene znakove, ma koliko ih god bilo // ulaz: input stream, znak za ignoriranje // izlaz: nista void SkipChar(istream &ifs, char *igme) { for (; index(igme, ifs.peek()) != NULL; ifs.ignore()); } // SkipChar(ifstream &, char *) // operator >> // ulaz: input stream, referenca na matricu // izlaz: referenca na input stream istream& operator>> (istream &ifs, Matrica &MOb) { while (ifs.peek() != EOF) // dok mozes citaj { double tmp; MOb.stupaca = 0; // najjednostavnije resetirati svaki put Double1D tmpRedak; // privremeni redak while (ifs && ifs.peek() != '\n') { ifs >> tmp; // ucitaj jedan znak tmpRedak.push_back(tmp); // i jedan po jedan u vektor MOb.stupaca++; SkipDelimiters(ifs); // preskoci " " ili "\t" } MOb.podaci.push_back(tmpRedak); // redak u kompletnu tablicu SkipDelimiterNL(ifs); // preskoci "\n" i sl. MOb.redaka++; } return ifs; } // istream& operator>> (istream &, Matrica &) // operator << // ulaz: output stream, referenca na matricu // izlaz: referenca na output stream ostream& operator<< (ostream &ofs, Matrica &MOb) { Double2D::iterator it; for (it = MOb.podaci.begin(); it != MOb.podaci.end(); ++it) { ostream_iterator out(ofs, "\t"); copy(it->begin(), it->end(), out); // iteriraj sve elemente ofs << endl; } return ofs; } // ostream& operator<< (ostream &, Matrica &) // glavna funkcija int main() { try { // stvorimo novi objekt Matrica burek; // upucamo vrijednosti cin >> burek; // ispisemo cout << "Lista elemenata prve matrice" << endl << burek << endl; // dohvatimo cout << "Dohvati matrica[1][3] = " << burek.Dohvati(1, 3) << endl << endl; // instanciramo novi objekt i inicijaliziramo vrijednostima starog Matrica burek2(burek); // postavimo jedan element burek.Postavi(2, 3, 0xdeadbeef); cout << "Lista elemenata promijenjene stare matrice" << endl << burek << endl; cout << "Lista elemenata nove matrice" << endl << burek2 << endl; // isprobavamo preopterecene operatore.. burek += burek2 * 2.0; cout << "Lista elemenata zbrojene matrice" << endl << burek << endl; // otvori dva streama ifstream prva("prva"); ifstream druga("druga"); if (prva && druga) { Matrica mnozi1; Matrica mnozi2; Matrica mnozi3; prva >> mnozi1; druga >> mnozi2; mnozi3 = mnozi1 * mnozi2; // pomnozi matrice cout << "Pomnozene matrice" << endl << mnozi3 << endl; // transponiraj matrice cout << "Transponirana" << endl << mnozi3.Transponiraj() << endl; } } // try catch (const char *msg) { cout << "Greska: " << msg << endl; return EXIT_FAILURE; } // catch return EXIT_SUCCESS; } // main