Serwis Edukacyjny w I-LO w Tarnowie Materiały dla uczniów liceum |
Wyjście Spis treści Wstecz Dalej
Autor artykułu: mgr Jerzy Wałaszek |
©2024 mgr Jerzy Wałaszek |
SPIS TREŚCI |
|
Podrozdziały |
W matematyce macierz ( ang. matrix ) jest prostokątną tablicą liczb, którą zwykle przedstawiamy następująco:
Liczby w macierzy ułożone są w poziomych wierszach oraz pionowych kolumnach. Liczba wierszy i liczba kolumn określa rozmiar macierzy ( ang. matrix size ). Macierze zapisujemy zwykle dużymi literami alfabetu, a w indeksie podajemy ich rozmiar. Liczby w macierzy są jej wyrazami ( ang. matrix elements/entries ) i posiadają indeksy określające numer wiersza i numer kolumny, w których się znajdują. Wyrazy macierzy zapisujemy małymi literami alfabetu:
Macierz zbudowaną z jednego wiersza lub jednej kolumny nazywamy wektorem ( ang. vector matrix ). Wektory zapisujemy skrótowo jako:
Macierz o jednakowej liczbie wierszy i kolumn nazywamy macierzą kwadratową ( ang. square matrix ):
Wyrazy macierzy o równych numerach wiersza i kolumny nazywamy przekątną główną macierzy ( ang. matrix main diagonal ), a liczba wierszy lub kolumn nazywana jest wtedy stopniem tej macierzy. Macierz kwadratowa stopnia czwartego wygląda następująco:
Macierz zerowa ( ang. zero matrix lub null matrix ) posiada wszystkie elementy zerowe:
Macierz jednostkowa, tożsamościowa, identycznościowa ( ang. unit matrix lub identity matrix ) jest macierzą kwadratową, której elementy przekątnej głównej są równe 1, a wszystkie pozostałe są równe 0:
Podmacierzą ( ang. submatrix ) nazywamy macierz, która powstaje z macierzy wyjściowej po usunięciu dowolnej liczby kolumn i wierszy:
Poniższy program deklaruje tablicę o rozmiarze 10×20 i wypełnia ją liczbami przypadkowymi o zakresie od 0 do 99.
Przykładowy program w języku C++
// Macierze // (C)2019 mgr Jerzy Wałaszek // Metody numeryczne //--------------------------- #include <iostream> #include <iomanip> #include <cstdlib> #include <ctime> using namespace std; // Program główny //--------------- int main() { setlocale(LC_ALL,""); cout << "Tablica statyczna o rozmiarze 10x20" << endl << "-----------------------------------" << endl << endl; // Definicja tablicy statycznej unsigned int A[10][20]; // Indeksy elementów unsigned i,j; // Inicjujemy generator pseudolosowy srand(time(NULL)); // Tablicę wypełniamy liczbami pseudolosowymi z zakresu 0...99 for(i = 0; i < 10; i++) // Wiersze for(j = 0; j < 20; j++) // Kolumny A[i][j] = rand() % 100; // Weświetlamy wyniki for(i = 0; i < 10; i++) { for(j = 0; j < 20; j++) cout << setw(3) << A[i][j]; cout << endl; } cout << endl; return 0; } |
Wynik |
Tablica statyczna o rozmiarze 10x20 ----------------------------------- 36 34 35 86 2 27 61 50 55 52 59 4 34 77 98 43 94 59 7 73 15 37 5 96 23 31 90 61 13 13 48 0 74 15 52 46 33 75 14 24 32 39 11 28 43 22 10 37 81 93 12 70 81 18 28 23 47 27 62 39 38 55 60 29 12 30 66 74 52 79 48 98 80 87 25 47 95 3 42 18 76 40 70 87 16 34 20 4 13 47 37 76 51 46 83 5 39 36 37 59 34 89 37 27 2 42 59 29 87 26 35 48 61 30 20 30 33 69 27 66 29 28 68 72 44 71 54 86 86 32 21 21 32 19 95 14 11 62 28 41 71 58 83 73 49 2 36 37 72 0 39 59 44 49 73 95 64 44 58 74 90 62 6 20 1 13 24 82 90 82 52 88 22 59 60 26 67 9 57 85 24 34 66 49 14 35 37 21 84 7 25 66 31 19 81 15 79 5 7 76 |
Pamiętaj, iż w języku C++ indeksy rozpoczynają się od 0, zatem element A[0][0] jest elementem w pierwszym wierszu i w pierwszej kolumnie macierzy.
Tablicę dynamiczną można stworzyć na kilka sposobów. Pierwszy z nich polega na zarezerwowaniu odpowiedniego obszaru pamięci i umieszczenie w nim tablicy, Po wykorzystaniu tablicy zarezerwowany dla niej obszar pamięci należy zwolnić.
Drugi program pokazuje, jak to zrobić w języku C++:
Przykładowy program w języku C++
// Macierze // (C)2019 mgr Jerzy Wałaszek // Metody numeryczne //--------------------------- #include <iostream> #include <iomanip> #include <cstdlib> #include <ctime> using namespace std; // Program główny //--------------- int main() { // Inicjujemy generator pseudolosowy srand(time(NULL)); // Generujemy rozmiar tablicy: // n - liczba wierszy: 5...15 // m - liczba kolumn: 10...20 int n = 5 + rand() % 11; int m = 10 + rand() % 11; // Tworzymy wskaźnik do wskaźników liczb całkowitych int ** A; // Tworzymy dynamicznie obszar na tablicę n wskaźników A = new int * [n]; // Tworzymy dynamiczne tablice dla każdego wiersza int i,j; for(i = 0; i < n; i++) A[i] = new int [m]; setlocale(LC_ALL,""); cout << "Tablica dynamiczna o rozmiarze " << n << "x" << m << endl << "------------------------------------" << endl << endl; // Tablicę wypełniamy liczbami pseudolosowymi z zakresu 0...99 for(i = 0; i < n; i++) // Wiersze for(j = 0; j < m; j++) // Kolumny A[i][j] = rand() % 100; // Wyświetlamy wyniki for(i = 0; i < n; i++) { for(j = 0; j < m; j++) cout << setw(3) << A[i][j]; cout << endl; } cout << endl; // Usuwamy tablice wierszy for(i = 0; i < n; i++) delete [] A[i]; // Usuwamy tablicę wskaźników delete [] A; return 0; } |
Wynik |
Tablica dynamiczna o rozmiarze 12x19 ------------------------------------ 22 61 20 80 10 97 86 84 41 26 64 66 7 92 85 76 55 0 90 44 76 77 14 51 18 16 63 42 94 93 27 43 15 35 6 7 6 36 2 51 47 67 70 71 35 17 3 15 44 77 23 4 12 45 36 5 95 66 9 78 67 68 40 88 24 62 36 43 19 54 3 20 95 56 18 80 95 91 76 65 83 33 61 69 37 56 12 0 21 89 95 9 28 4 4 77 14 84 47 32 42 40 91 20 98 26 42 83 3 55 82 95 18 79 92 3 56 94 50 41 47 36 51 26 21 21 17 74 52 52 12 53 91 37 45 97 4 84 41 8 34 8 75 96 37 71 68 38 28 40 38 88 90 71 78 94 85 36 94 95 46 30 97 95 1 25 97 83 36 50 47 21 21 78 61 46 73 14 73 9 70 97 15 81 81 70 5 45 44 87 30 7 50 59 40 42 4 72 59 68 94 56 88 20 19 57 27 71 62 86 95 90 57 37 3 19 18 54 62 15 19 17 71 67 86 58 71 18 |
Macierz może również zostać odwzorowana jako klasa języka C++. W klasie można zdefiniować różne operacje na zawartej w niej macierzy. Plik definiujący klasę można używać jako plik nagłówkowy w programach przetwarzających macierze. Zaletą klasy jest to, iż prosto możemy zdefiniować w programie wiele różnych macierzy.
Poniższy program demonstruje przykładową prostą klasę macierzy liczb całkowitych. Klasa ta wspiera operacje przypisywania wartości elementom macierzy oraz odczytywania wartości elementów ( dla prostoty klasa nie sprawdza błędów ). Zwróć uwagę, iż zarezerwowano obszar dla tablicy jednowymiarowej. Tak też można.
Przykładowy program w języku C++
// Macierze // (C)2019 mgr Jerzy Wałaszek // Metody numeryczne //--------------------------- #include <iostream> #include <iomanip> #include <cstdlib> #include <ctime> using namespace std; // Definicja klasy, może być w pliku nagłówkowym //---------------------------------------------- #ifndef _matrix_class #define _matrix_class class matrix { private: int n,m; // Rozmiar macierzy int * A; // Elementy public: matrix(int r, int c); // Konstruktor ~matrix(); // Destruktor void setv(int r, int c, int v); int getv(int r, int c); }; // Konstruktor - tworzy macierz o podanych wymiarach: // r - liczba wierszy // c - liczba kolumn //--------------------------------------------------- matrix::matrix(int r, int c) { n = r; m = c; A = new int [n * m]; } // Destruktor - usuwa macierz i zwraca zajętą przez nią pamięć //------------------------------------------------------------ matrix::~matrix() { delete [] A; } // Ustawia wartość elementu // r - numer wiersza // c - numer kolumny // v - wartość dla elementu //------------------------- void matrix::setv(int r, int c, int v) { A[r * m + c] = v; } // Zwraca wartość elementu // r - numer wiersza // c - numer kolumny //------------------------- int matrix::getv(int r, int c) { return A[r * m + c]; } #endif // _matrix_class // Program główny //--------------- int main() { // Inicjujemy generator pseudolosowy srand(time(NULL)); // Generujemy rozmiar tablicy: // n - liczba wierszy: 5...15 // m - liczba kolumn: 10...20 int n = 5 + rand() % 11; int m = 10 + rand() % 11; // Tworzymy macierz matrix A(n,m); // Macierz wypełniamy liczbami od -99 do 99 int i,j; for(i = 0; i < n; i++) for(j = 0; j < m; j++) A.setv(i,j,-99+rand() % 199); // Wyświetlamy macierz setlocale(LC_ALL,""); cout << "Klasa macierzy o rozmiarze " << n << "x" << m << endl << "--------------------------------" << endl << endl; for(i = 0; i < n; i++) { for(j = 0; j < m; j++) cout << setw(4) << A.getv(i,j); cout << endl; } cout << endl; return 0; } |
Wynik |
Klasa macierzy o rozmiarze 10x15 -------------------------------- 55 -98 -58 16 10 -13 87 26 -51 -20 0 20 -76 68 -91 0 20 -76 68 -91 -85 -6 96 75 96 32 -38 -18 -79 -92 32 -38 -18 -79 -92 73 99 62 -63 37 73 -65 -19 30 17 73 -65 -19 30 17 -29 75 55 57 99 85 35 -36 73 -43 85 35 -36 73 -43 -35 -57 -45 -35 83 -89 4 65 6 10 -89 4 65 6 10 -27 67 64 -49 -39 -95 -57 -75 -54 60 -95 -57 -75 -54 60 -44 86 22 -16 14 61 -80 -57 18 -40 61 -80 -57 18 -40 -46 -69 25 -89 7 -8 -3 33 -80 27 -8 -3 33 -80 27 78 -78 48 85 -90 54 84 75 -94 59 54 84 75 -94 59 48 -60 -2 43 -22 78 39 -94 -20 52 |
Lepszym pomysłem jest wykorzystanie klasy szablonowej. Klasa szablonowa nie określa typu elementów - robi to program użytkownika w momencie tworzenia zmiennej na podstawie szablonu klasy. Dzięki temu możemy w prosty sposób otrzymać macierz o dowolnym typie elementów.
Poniższy przykład programu definiuje klasę szablonową macierzy, następnie na jej podstawie tworzy macierz liczb typu double, wypełnia ją pseudolosowymi wartościami i wyświetla jej zawartość. Wszystko jest maksymalnie uproszczone.
Przykładowy program w języku C++
// Macierze // (C)2019 mgr Jerzy Wałaszek // Metody numeryczne //--------------------------- #include <iostream> #include <iomanip> #include <cstdlib> #include <ctime> using namespace std; // Definicja klasy, może być w pliku nagłówkowym //---------------------------------------------- #ifndef _matrix_class #define _matrix_class template <class T> class matrix { private: int n,m; // Rozmiar macierzy T * A; // Elementy public: matrix(int r, int c); // Konstruktor ~matrix(); // Destruktor void setv(int r, int c, T v); T getv(int r, int c); }; // Konstruktor - tworzy macierz o podanych wymiarach: // r - liczba wierszy // c - liczba kolumn //--------------------------------------------------- template <class T> matrix<T>::matrix(int r, int c) { n = r; m = c; A = new T [n * m]; } // Destruktor - usuwa macierz i zwraca zajętą przez nią pamięć //------------------------------------------------------------ template <class T> matrix<T>::~matrix() { delete [] A; } // Ustawia wartość elementu // r - numer wiersza // c - numer kolumny // v - wartość dla elementu //------------------------- template <class T> void matrix<T>::setv(int r, int c, T v) { A[r * m + c] = v; } // Zwraca wartość elementu // r - numer wiersza // c - numer kolumny //------------------------- template <class T> T matrix<T>::getv(int r, int c) { return A[r * m + c]; } #endif // _matrix_class // Program główny //--------------- int main() { // Inicjujemy generator pseudolosowy srand(time(NULL)); // Generujemy rozmiar tablicy: // n - liczba wierszy: 5...15 // m - liczba kolumn: 5...15 int n = 5 + rand() % 11; int m = 5 + rand() % 11; // Tworzymy macierz matrix<double> A(n,m); // Macierz wypełniamy liczbami pseudolosowymi od 0 do 9.99 int i,j; for(i = 0; i < n; i++) for(j = 0; j < m; j++) A.setv(i,j,(rand() % 1000) / 100.0); // Wyświetlamy macierz setlocale(LC_ALL,""); cout << setprecision(2) << fixed; cout << "Klasa szablonowa macierzy o rozmiarze " << n << "x" << m << endl << "-------------------------------------------" << endl << endl; for(i = 0; i < n; i++) { for(j = 0; j < m; j++) cout << setw(5) << A.getv(i,j); cout << endl; } cout << endl; return 0; } |
Wynik |
Klasa szablonowa macierzy o rozmiarze
12x13 ------------------------------------------- 8.40 8.88 4.15 1.27 2.23 5.34 6.05 5.91 7.75 6.53 6.92 0.58 0.24 1.01 2.01 6.73 4.22 8.37 4.53 7.18 2.58 9.83 7.24 4.40 4.09 2.83 7.34 9.16 5.37 0.04 7.90 0.38 0.02 9.60 8.33 1.45 8.97 5.95 8.09 3.31 8.59 5.02 2.99 4.04 6.39 4.76 6.70 7.69 5.96 8.54 6.21 5.00 2.14 2.55 7.51 7.34 1.31 0.74 4.13 6.64 7.95 7.63 4.91 6.78 5.03 2.59 8.26 9.01 8.17 3.84 1.33 8.87 8.77 3.80 1.63 1.80 6.70 5.81 1.81 0.43 7.87 9.33 1.05 8.98 3.40 1.15 8.70 1.86 1.76 8.26 7.28 0.30 9.20 0.64 2.78 1.57 2.18 8.97 0.18 2.54 9.10 0.05 7.61 2.92 0.13 0.87 0.76 0.58 2.92 6.16 2.54 8.96 7.55 6.84 6.64 1.27 4.10 5.87 3.61 4.50 7.66 5.22 9.93 1.97 2.49 4.83 3.83 5.78 7.92 0.50 7.69 5.46 3.37 0.10 3.01 0.57 0.68 4.88 1.74 2.69 0.73 3.01 5.29 6.00 5.70 3.86 0.25 6.60 8.99 9.83 8.55 0.54 2.07 4.44 5.58 1.42 |
W dalszej części artykułu będziemy wykorzystywali klasę szablonową z odpowiednimi modyfikacjami, ponieważ jest najbardziej ogólna.
Podamy tutaj proste sposoby wprowadzania danych do programu przetwarzającego macierze. Dane można umieszczać bezpośrednio w programie, w pliku lub wprowadzać je przez strumień wejścia.
Dane umieszczone w programie nie są specjalnie wygodnym sposobem definiowania zawartości macierzy, ponieważ zmiana danych wymaga modyfikacji programu. Niemniej jednak ten sposób może być czasem przydatny.
Poniższy program tworzy macierz jednostkową i wyświetla jej zawartość:
Przykładowy program w języku C++
// Macierze // (C)2019 mgr Jerzy Wałaszek // Metody numeryczne //--------------------------- #include <iostream> #include <iomanip> #include <cstdlib> #include <ctime> using namespace std; // Definicja klasy, może być w pliku nagłówkowym //---------------------------------------------- #ifndef _matrix_class #define _matrix_class template <class T> class matrix { private: int n,m,s; // Rozmiar macierzy T * A; // Elementy public: matrix(int r, int c); // Konstruktor ~matrix(); // Destruktor void makeIdent(void); // Macierz jednostkowa T getv(int r, int c); }; // Konstruktor - tworzy macierz o podanych wymiarach: // r - liczba wierszy // c - liczba kolumn //--------------------------------------------------- template <class T> matrix<T>::matrix(int r, int c) { n = r; m = c; s = n * m; A = new T [s]; } // Destruktor - usuwa macierz i zwraca zajętą przez nią pamięć //------------------------------------------------------------ template <class T> matrix<T>::~matrix() { delete [] A; } // Tworzy macierz jednostkową //------------------------- template <class T> void matrix<T>::makeIdent() { int i; for(i = 0; i < s; i++) A[i] = (T) 0; for(i = 0; i < n; i++) A[i * m + i] = (T) 1; } // Zwraca wartość elementu // r - numer wiersza // c - numer kolumny //------------------------- template <class T> T matrix<T>::getv(int r, int c) { return A[r * m + c]; } #endif // _matrix_class // Program główny //--------------- int main() { // Inicjujemy generator pseudolosowy srand(time(NULL)); // Generujemy rozmiar macierzy: // n - liczba wierszy i kolumn: 10...20 int n,i,j; n = 10 + rand() % 11; // Tworzymy macierz kwadratową matrix<int> A(n,n); // Tworzymy macierz jednostkową A.makeIdent(); // Wyświetlamy macierz setlocale(LC_ALL,""); cout << "Macierz jednostkowa o rozmiarze " << n << "x" << n << endl << "-------------------------------------" << endl << endl; for(i = 0; i < n; i++) { for(j = 0; j < n; j++) cout << setw(2) << A.getv(i,j); cout << endl; } cout << endl; return 0; } |
Wynik |
Macierz jednostkowa o rozmiarze 20x20 ------------------------------------- 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 |
Następne dwie metody odczytują dane dla macierzy ze strumienia, Pierwsza metoda odczytuje dane z pliku dane.txt, który należy umieścić w katalogu projektowym, jeśli pracujesz w edytorze Code Blocks, lub w katalogu z programem, jeśli uruchamiasz program z poziomu konsoli lub menedżera plików.
Dane są skonstruowane następująco:
Przykładowe dane:
Przekopiuj plik dane.txt do odpowiedniego katalogu.
Poniższy program tworzy macierz na podstawie danych z pliku. Zakładamy, że dane są liczbami całkowitymi bez znaku ( typ macierzy musi się zgadzać z typem danych w pliku ). Następnie program wyświetla zawartość wczytanej macierzy.
Przykładowy program w języku C++
// Macierze // (C)2019 mgr Jerzy Wałaszek // Metody numeryczne //--------------------------- #include <iostream> #include <fstream> #include <iomanip> using namespace std; // Definicja klasy, może być w pliku nagłówkowym //---------------------------------------------- #ifndef _matrix_class #define _matrix_class template <class T> class matrix { private: int n,m,s; // Rozmiar macierzy T * A; // Elementy public: matrix(); // Konstruktor ~matrix(); // Destruktor T getv(int r, int c); int rows(); // Zwraca liczbę wierszy macierzy int cols(); // Zwraca liczbę kolumn macierzy }; // Konstruktor - tworzy macierz z pliku dane.txt //---------------------------------------------- template <class T> matrix<T>::matrix() { ifstream fin; // Strumień wejścia z pliku fin.open("dane.txt",ifstream::in); // Otwieramy strumień do odczytu fin >> n >> m; // Odczytujemy ze strumienia wymiary macierzy s = n * m; A = new T [s]; // Rezerwujemy pamięć na macierz for(int i = 0; i < s; i++) fin >> A[i]; // Wczytujemy wyrazy do macierzy fin.close(); // Zamykamy strumień } // Destruktor - usuwa macierz i zwraca zajętą przez nią pamięć //------------------------------------------------------------ template <class T> matrix<T>::~matrix() { delete [] A; } // Zwraca wartość elementu // r - numer wiersza // c - numer kolumny //------------------------- template <class T> T matrix<T>::getv(int r, int c) { return A[r * m + c]; } // Zwraca liczbę wierszy w macierzy //--------------------------------- template <class T> int matrix<T>::rows() { return n; } // Zwraca liczbę kolumn w macierzy //--------------------------------- template <class T> int matrix<T>::cols() { return m; } #endif // _matrix_class // Program główny //--------------- int main() { // Tworzymy macierz matrix<int> A; // Wyświetlamy macierz int i,j; setlocale(LC_ALL,""); cout << "Macierz z pliku o rozmiarze " << A.rows() << "x" << A.cols() << endl << "---------------------------------" << endl << endl; for(i = 0; i < A.rows(); i++) { for(j = 0; j < A.cols(); j++) cout << setw(4) << A.getv(i,j); cout << endl; } cout << endl; return 0; } |
Wynik |
Macierz z pliku o rozmiarze 10x15 --------------------------------- 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 7 0 9 6 4 7 2 5 3 1 0 2 8 2 3 8 8 6 2 3 1 0 8 5 4 8 2 9 9 2 9 6 9 2 3 2 1 9 6 8 2 3 4 5 1 8 9 5 6 3 2 2 2 6 11 5 7 9 12 6 0 7 8 2 7 3 5 5 1 8 9 3 3 2 0 9 7 2 5 5 5 2 2 2 1 9 8 0 0 0 4 444 7 6 8 9 2 3 6 8 8 888 92 43 15 1 3 66 87 51 62 88 92 83 99 11 13 6 55 6 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Kolejny program jest właściwie identyczny z poprzednim. Różnica polega na tym, iż dane dla macierzy odczytywane są ze standardowego strumienia. Poniższe dane skopiuj do schowka, uruchom program i wklej je do okna konsoli ( Windows: Ctrl+V, Linuks Ctrl+Shift+V ):
Dane wejściowe:
10 15 126 22 36 4 54 6 7 88 96 0 13 25 3 47 52 75 0 95 62 46 73 21 5 32 17 0 27 8 29 34 82 85 6 21 343 16 28 8 5 44 83 29 911 93 23 99 655 96 222 32 24 1 96 68 8 21 3 4 53 18 81 93 598 6 32 25 29 21 63 11 56 71 92 12 6 0 734 8 27 7 37 5 53 1 89 9 34 37 22 0 929 7 26 5 533 5 2 29 22 15 92 83 47 28 0 4 444 7 6 8 9 26 3 69 86 87 888 92 43 15 51 34 66 87 51 62 88 92 83 99 11 13 6 55 6 19 2 3 4 5 6 74 8 9 10 11 12 13 14 15 |
Przykładowy program w języku C++
// Macierze // (C)2019 mgr Jerzy Wałaszek // Metody numeryczne //--------------------------- #include <iostream> #include <iomanip> using namespace std; // Definicja klasy, może być w pliku nagłówkowym //---------------------------------------------- #ifndef _matrix_class #define _matrix_class template <class T> class matrix { private: int n,m,s; // Rozmiar macierzy T * A; // Elementy public: matrix(); // Konstruktor ~matrix(); // Destruktor T getv(int r, int c); int rows(); // Zwraca liczbę wierszy macierzy int cols(); // Zwraca liczbę kolumn macierzy }; // Konstruktor - tworzy macierz ze strumienia cin //----------------------------------------------- template <class T> matrix<T>::matrix() { cin >> n >> m; // Odczytujemy ze strumienia wymiary macierzy s = n * m; A = new T [s]; // Rezerwujemy pamięć na macierz for(int i = 0; i < s; i++) cin >> A[i]; // Wczytujemy wyrazy do macierzy } // Destruktor - usuwa macierz i zwraca zajętą przez nią pamięć //------------------------------------------------------------ template <class T> matrix<T>::~matrix() { delete [] A; } // Zwraca wartość elementu // r - numer wiersza // c - numer kolumny //------------------------- template <class T> T matrix<T>::getv(int r, int c) { return A[r * m + c]; } // Zwraca liczbę wierszy w macierzy //--------------------------------- template <class T> int matrix<T>::rows() { return n; } // Zwraca liczbę kolumn w macierzy //--------------------------------- template <class T> int matrix<T>::cols() { return m; } #endif // _matrix_class // Program główny //--------------- int main() { // Wyświetlamy macierz int i,j; setlocale(LC_ALL,""); cout << "Wpisz dane dla macierzy:" << endl; // Tworzymy macierz z wczytaniem jej ze strumienia matrix<int> A; cout << endl << "Macierz ze strumienia o rozmiarze " << A.rows() << "x" << A.cols() << endl << "---------------------------------------" << endl << endl; for(i = 0; i < A.rows(); i++) { for(j = 0; j < A.cols(); j++) cout << setw(4) << A.getv(i,j); cout << endl; } cout << endl; return 0; } |
Wynik |
Wpisz dane dla macierzy: 10 15 126 22 36 4 54 6 7 88 96 0 13 25 3 47 52 75 0 95 62 46 73 21 5 32 17 0 27 8 29 34 82 85 6 21 343 16 28 8 5 44 83 29 911 93 23 99 655 96 222 32 24 1 96 68 8 21 3 4 53 18 81 93 598 6 32 25 29 21 63 11 56 71 92 12 6 0 734 8 27 7 37 5 53 1 89 9 34 37 22 0 929 7 26 5 533 5 2 29 22 15 92 83 47 28 0 4 444 7 6 8 9 26 3 69 86 87 888 92 43 15 51 34 66 87 51 62 88 92 83 99 11 13 6 55 6 19 2 3 4 5 6 74 8 9 10 11 12 13 14 15 Macierz ze strumienia o rozmiarze 10x15 --------------------------------------- 126 22 36 4 54 6 7 88 96 0 13 25 3 47 52 75 0 95 62 46 73 21 5 32 17 0 27 8 29 34 82 85 6 21 343 16 28 8 5 44 83 29 911 93 23 99 655 96 222 32 24 1 96 68 8 21 3 4 53 18 81 93 598 6 32 25 29 21 63 11 56 71 92 12 6 0 734 8 27 7 37 5 53 1 89 9 34 37 22 0 929 7 26 5 533 5 2 29 22 15 92 83 47 28 0 4 444 7 6 8 9 26 3 69 86 87 888 92 43 15 51 34 66 87 51 62 88 92 83 99 11 13 6 55 6 19 2 3 4 5 6 74 8 9 10 11 12 13 14 15 |
W dalszej części artykułu będziemy stosować tę ostatnią metodę do wprowadzania danych macierzowych w przykładowych programach.
Na macierzach można wykonywać różne operacje arytmetyczne, które krótko opisujemy poniżej:
Jeśli w macierzy zamienimy wiersze z kolumnami to otrzymamy macierz transponowaną. Operację transponowania macierzy ( ang. matrix transposition ) zapisujemy dużą literą T w indeksie górnym:
Poniższy program wczytuje macierz ze standardowego wejścia i dokonuje jej transpozycji. Dane dla macierzy są pobierane ze strumienia wejściowego.
Przykładowe dane ( przekopiuj je do schowka i wklej w programie ):
Macierz:
Dane wejściowe: 4 6 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
Przykładowy program w języku C++ // Macierze // (C)2019 mgr Jerzy Wałaszek // Metody numeryczne //--------------------------- #include <iostream> #include <iomanip> using namespace std; // Definicja klasy, może być w pliku nagłówkowym //---------------------------------------------- #ifndef _matrix_class #define _matrix_class template <class T> class matrix { private: int s; // Rozmiar macierzy T * A; // Elementy public: int n,m; // Liczba wierszy i kolumn matrix(); // Konstruktor ~matrix(); // Destruktor T getv(int r, int c); void transpose(); // Dokonuje transpozycji macierzy }; // Konstruktor - tworzy macierz ze strumienia cin //----------------------------------------------- template <class T> matrix<T>::matrix() { cin >> n >> m; // Rozmiar macierzy s = n * m; A = new T [s]; // Rezerwujemy pamięć na macierz n x m for(int i = 0; i < s; i++) cin >> A[i]; // Wczytujemy wyrazy macierzy } // Destruktor - usuwa macierz i zwraca zajętą przez nią pamięć //------------------------------------------------------------ template <class T> matrix<T>::~matrix() { delete [] A; } // Zwraca wartość elementu // r - numer wiersza // c - numer kolumny //------------------------- template <class T> T matrix<T>::getv(int r, int c) { return A[r * m + c]; } // Transponuje macierz //-------------------- template <class T> void matrix<T>::transpose() { T * B = new T[s]; // Tymczasowa macierz o tej samej liczbie elementów int i,j; for(i = 0; i < n; i++) for(j = 0; j < m; j++) B[j * n + i] = A[i * m + j]; delete [] A; // Usuwamy starą macierz A = B; // Podmieniamy ją macierzą transponowaną swap(n,m); // Zamieniamy wiersze z kolumnami } #endif // _matrix_class // Program główny //--------------- int main() { // Wczytujemy dane dla macierzy setlocale(LC_ALL,""); cout << "Wpisz dane dla macierzy:" << endl << endl; matrix<int> A; cout << endl << "Macierz przed transponowaniem ma wymiary " << A.n << " x " << A.m << endl << "----------------------------------------------" << endl << endl; for(int i = 0; i < A.n; i++) { for(int j = 0; j < A.m; j++) cout << setw(6) << A.getv(i,j); cout << endl; } // Transponujemy macierz A.transpose(); cout << endl << endl << "Macierz po transponowaniu ma wymiary " << A.n << " x " << A.m << endl << "------------------------------------------" << endl << endl; for(int i = 0; i < A.n; i++) { for(int j = 0; j < A.m; j++) cout << setw(6) << A.getv(i,j); cout << endl; } cout << endl << endl; return 0; } |
Wynik |
Wpisz dane dla macierzy: 4 6 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 Macierz przed transponowaniem ma wymiary 4 x 6 ---------------------------------------------- 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 Macierz po transponowaniu ma wymiary 6 x 4 ------------------------------------------ 1 7 13 19 2 8 14 20 3 9 15 21 4 10 16 22 5 11 17 23 6 12 18 24 |
Macierze można mnożyć przez liczbę. Wynikiem takiego mnożenia jest macierz, której wszystkie elementy zostały pomnożone przez daną liczbę:
Dodawać można macierze o tych samych wymiarach. Wynikiem dodawania jest macierz, której elementy są sumami odpowiadających sobie elementów obu macierzy:
Mnożenie w przypadku macierzy jest trochę bardziej skomplikowane. Aby można było pomnożyć dwie macierze, muszą one spełniać pewien warunek, mianowicie, jeśli pierwsza macierz A ma m kolumn, to druga macierz B musi posiadać m wierszy:
Macierz wynikowa C posiada tyle wierszy, ile miała macierz A i tyle kolumn, ile miała macierz B.
Zasadę mnożenia najlepiej jest zrozumieć na prostym przykładzie. Mamy dwie macierze:
Macierz A ustawiamy po lewej stronie macierzy C, a macierz B ustawiamy ponad macierzą C:
1 | 3 | 5 | 7 | 9 | ||||||||||
B = | 11 | 13 | 15 | 17 | 19 | |||||||||
21 | 23 | 25 | 27 | 29 | ||||||||||
31 | 33 | 35 | 37 | 39 | ||||||||||
0 | 2 | 4 | 6 | ? | ? | ? | ? | ? | ||||||
A = | 8 | 10 | 12 | 14 | C = | ? | ? | ? | ? | ? | ||||
16 | 18 | 20 | 22 | ? | ? | ? | ? | ? |
Kolejne elementy cij macierzy C obliczamy jako sumę iloczynów kolejnych elementów z wiersza i-tego macierzy A przez kolejne elementy z kolumny j-tej macierzy B. Na przykład:
1 | 3 | 5 | 7 | 9 | ||||||||||
B = | 11 | 13 | 15 | 17 | 19 | |||||||||
21 | 23 | 25 | 27 | 29 | ||||||||||
31 | 33 | 35 | 37 | 39 | ||||||||||
0 | 2 | 4 | 6 | 292 | ? | ? | ? | ? | ||||||
A = | 8 | 10 | 12 | 14 | C = | ? | ? | ? | ? | ? | ||||
16 | 18 | 20 | 22 | ? | ? | ? | ? | ? |
W ten sam sposób obliczamy pozostałe elementy macierzy C.
1 | 3 | 5 | 7 | 9 | ||||||||||
B = | 11 | 13 | 15 | 17 | 19 | |||||||||
21 | 23 | 25 | 27 | 29 | ||||||||||
31 | 33 | 35 | 37 | 39 | ||||||||||
0 | 2 | 4 | 6 | 292 | 316 | 340 | 364 | 388 | ||||||
A = | 8 | 10 | 12 | 14 | C = | 804 | 892 | 980 | 1068 | 1156 | ||||
16 | 18 | 20 | 22 | 1316 | 1468 | 1620 | 1772 | 1924 |
Poniższy program mnoży dwie macierze i wyświetla wynik mnożenia. Dane wejściowe są odczytywane ze strumienia wejściowego. Dane macierzy poprzedzone są dwoma liczbami, które oznaczają liczbę wierszy i kolumn. Za tymi liczbami należy umieścić odpowiednią liczbę elementów dla macierzy. Elementy są liczbami całkowitymi. Program nie sprawdza poprawności danych.
Przykładowe dane ( przekopiuj je do schowka i wklej w programie ):
Macierze:
Dane wejściowe:
3 4 0 2 4 6 8 10 12 14 16 18 20 22 4 5 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 |
Przykładowy program w języku C++
// Macierze // (C)2019 mgr Jerzy Wałaszek // Metody numeryczne //--------------------------- #include <iostream> #include <iomanip> using namespace std; // Definicja klasy, może być w pliku nagłówkowym //---------------------------------------------- #ifndef _matrix_class #define _matrix_class template <class T> class matrix { private: int s; // Rozmiar macierzy T * A; // Elementy macierzy A public: int n,m; // Liczba wierszy i kolumn matrix(); // Konstruktor matrix(int r, int c); // Konstruktor ~matrix(); // Destruktor T getv(int r, int c); void multiply(matrix<T> & a, matrix<T> & b); }; // Konstruktor - tworzy macierz ze strumienia cin //----------------------------------------------- template <class T> matrix<T>::matrix() { cin >> n >> m; // Rozmiar macierzy s = n * m; A = new T [s]; // Rezerwujemy pamięć na macierz n x m for(int i = 0; i < s; i++) cin >> A[i]; // Wczytujemy wyrazy macierzy } // Konstruktor - tworzy pustą macierz na podstawie wymiarów //--------------------------------------------------------- template <class T> matrix<T>::matrix(int r, int c) { n = r; m = c; s = n * m; A = new T [s]; // Rezerwujemy pamięć na macierz n x m } // Destruktor - usuwa macierz i zwraca zajętą przez nią pamięć //------------------------------------------------------------ template <class T> matrix<T>::~matrix() { delete [] A; } // Zwraca wartość elementu // r - numer wiersza // c - numer kolumny //------------------------- template <class T> T matrix<T>::getv(int r, int c) { return A[r * m + c]; } // Mnoży macierze //-------------------- template <class T> void matrix<T>::multiply(matrix<T> & a, matrix<T> & b) { T sum; int i,j,k; for(i = 0; i < n; i++) for (j= 0; j < m; j++) { sum = 0; for(k = 0;k < a.m; k++) sum += a.getv(i,k) * b.getv(k,j); A[i * m + j] = sum; } } #endif // _matrix_class // Program główny //--------------- int main() { // Wczytujemy dane dla macierzy setlocale(LC_ALL,""); cout << "Wpisz dane dla macierzy:" << endl << endl; matrix<int> A; matrix<int> B; // Ustawiamy macierz wyniku matrix<int> C(A.n,B.m); cout << endl << "Mnożenie macierzy" << endl << "-----------------" << endl << endl; cout << "Macierz A" << A.n << "x" << A.m << endl; for(int i = 0; i < A.n; i++) { for(int j = 0; j < A.m; j++) cout << setw(6) << A.getv(i,j); cout << endl; } cout << endl; cout << "Macierz B" << B.n << "x" << B.m << endl; for(int i = 0; i < B.n; i++) { for(int j = 0; j < B.m; j++) cout << setw(6) << B.getv(i,j); cout << endl; } cout << endl; // Mnożymy macierz A przez macierz B i wynik wpisujemy do macierzy C C.multiply(A,B); cout << "Wynik mnożenia w macierzy C" << C.n << "x" << C.m << endl; for(int i = 0; i < C.n; i++) { for(int j = 0; j < C.m; j++) cout << setw(6) << C.getv(i,j); cout << endl; } cout << endl; return 0; } |
Wynik |
Wpisz dane dla macierzy: 3 4 0 2 4 6 8 10 12 14 16 18 20 22 4 5 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 Mnożenie macierzy ----------------- Macierz A3x4 0 2 4 6 8 10 12 14 16 18 20 22 Macierz B4x5 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 Wynik mnożenia w macierzy C3x5 292 316 340 364 388 804 892 980 1068 1156 1316 1468 1620 1772 1924 |
Zespół Przedmiotowy Chemii-Fizyki-Informatyki w I Liceum Ogólnokształcącym im. Kazimierza Brodzińskiego w Tarnowie ul. Piłsudskiego 4 ©2024 mgr Jerzy Wałaszek |
Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone
pod warunkiem podania źródła oraz niepobierania za to pieniędzy.
Pytania proszę przesyłać na adres email:
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.
Informacje dodatkowe.