Serwis Edukacyjny
w I-LO w Tarnowie
obrazek

Materiały dla uczniów liceum

  Wyjście       Spis treści       Wstecz       Dalej  

obrazek

Autor artykułu: mgr Jerzy Wałaszek

©2024 mgr Jerzy Wałaszek
I LO w Tarnowie

obrazek

Równania

Macierze

SPIS TREŚCI
Podrozdziały

Definicje

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:


Na początek:  podrozdziału   strony 

Tablice dynamiczne w języku C++

 
Macierz w języku C++ jest reprezentowana przez tablicę. Tablicę możemy deklarować statycznie lub dynamicznie. Deklaracja statyczna wymaga znajomości rozmiaru tablicy w momencie tworzenia programu.

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.


Na początek:  podrozdziału   strony 

Wprowadzanie danych do macierzy

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:

5 6
1 6 8 7 5 6
8 8 9 2 1 0
3 1 4 7 2 1
2 2 0 7 9 1
0 0 0 2 2 2

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 początek:  podrozdziału   strony 

Operacje na macierzach

Na macierzach można wykonywać różne operacje arytmetyczne, które krótko opisujemy poniżej:


Transpozycja

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

Mnożenie przez skalar

Macierze można mnożyć przez liczbę. Wynikiem takiego mnożenia jest macierz, której wszystkie elementy zostały pomnożone przez daną liczbę:


Dodawanie macierzy

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 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:

An × m × Bm × p = Cn × p

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:

obrazek

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

Na początek:  podrozdziału   strony 

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: i-lo@eduinf.waw.pl

Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.

Informacje dodatkowe.