ГЛАВА 9. Преобразование и построение матриц

Матрица – это прямоугольная таблица, образованная из элементов некоторого множества и состоящая из n строк и m столбцов [16]:

(9.1)

Такая таблица называется прямоугольной матрицей размера (n×m) или (n ×m)-матрицей с элементами . Элемент расположен в i -й строке и j -м столбце. При n = m матрица называется квадратной, а число n – ее порядком.

При работе с матрицами следует обратить внимание на то, определены или нет размеры матрицы до начала выполнения программы. Рассмотрим два случая выделения памяти под элементы матрицы.

§ Размерность матрицы определена перед выполнением программы

Если размерность матрицы задана заранее, например ее размерность равна 8, то используется описание:

Тип имя_матрицы [8][8];

В этом случае происходит статическое выделение памяти, то есть память выделяется до выполнения программы. При объявлении указанного объекта создается указатель с именем имя_матрицы, выделяется место под 8 указателей типа * Тип и адрес первого байта становится значением переменной
имя_матрицы. Каждый из 8 указателей имя_матрицы [i] связан с выделенной памятью под 8 объектов типа Тип и адрес первого байта каждой выделенной области становится значением соответствующего объекта имя_матрицы [i] [24, 32].

Действия операционной системы может быть схематически отображено следующим образом (рис. 9.1):

Рис. 9.1. Иллюстрация статического выделения памяти под элементы матрицы

§ Размерность матрицы не определена перед выполнением программы

Поскольку размеры матрицы не определены до начала выполнения программы, следует использовать динамическое выделение памяти под элементы матрицы, то есть выделение памяти во время выполнения программы.

Если размерность матрицы заранее неизвестна, то для ее описания используется указатель типа указатель на * Тип.

Тип ** имя_матрицы;

В этом случае создается только переменная имя_матрицы типа Тип**. Когда определено число строк (n) и число столбцов (m) матрицы, с помощью операции new выделяется место под n переменных типа Тип*:

имя_матрицы = new Тип* [n];

то есть создается массив имя_матрицы [i]. Затем, для каждого элемента имя_матрицы [i] с помощью той же операции new выделяется место под n элементов типа Тип. Окончательно это может быть оформлено в виде следующего фрагмента:

Тип** имя_матрицы;

имя_матрицы = new Тип* [n];

for(i=0; i<m; i++)

имя_матрицы [i] = new Тип [m];

Иными словами, проводятся те операции, которые в первом случае выполняет операционная система.

При преобразовании и построении матриц целесообразно выполнять следующие действия:

а) Размерность матрицы и значение ее элементов необходимо читать из файла, так как для ввода с клавиатуры это слишком большой объем информации.

б) Печать матрицы следует оформить в виде отдельной функции, причем оформить шаблонную функцию для того, чтобы можно было печатать матрицы любого типа.

В определении шаблона функций применяется служебное слово template. Для параметризации используется список формальных параметров, который заключается в угловые скобки < >. Каждый формальный параметр шаблона обозначается служебным словом class, за которым следует имя параметра (идентификатор). Каждый параметр обязательно должен присутствовать в заголовке функции. При обращении к функции формальные параметры заменяются фактическими параметрами соответствующего типа.

Листинг 9.1. В программе из файла с именем “input.txt” читаются две матрицы размером 3 × 5. Одна из них вещественная, а другая целочисленная. Причем у вещественной матрицы оставляется только два знака после запятой с округлением.

//L9_1.cpp

#include «stdafx.h» // Файлы, помещенные в данный файл заголовка, будут

// предварительно откомпилированы.

#include <fstream>

#include <iostream>

using namespace std;

// Прототип шаблонной функции можно записать в две строки:

template <class pp> // Введение параметров шаблона

void print_matrix(pp **a, int n, int m);

int _tmain() // Компилятор создаст либо функцию main(), либо функцию // wmain() в зависимости от установок UNICODE.

{

setlocale(LC_CTYPE,"russian");

int n,m,i,j;

double **A; // Указатель, который будет связан

// с матрицей А.

ifstream ff("input.txt");

ff>>n>>m;

A=new double*[n]; // Идентификация указателя А и запрос

// памяти под n указателей типа double*.

for(i=0; i<n; i++)

A[i]=new double[m]; // Идентификация указателя А[i] и запрос

//памяти под m указателей типа double.

for(i=0; i<n; i++)

for(j=0; j<m; j++)

ff>>A[i][j];

cout<<"Исходная матрица\n";

print_matrix(A,n,m);

int **X; // Указатель, который будет связан с

//матрицей X.

X=new int*[n]; // Идентификация указателя X и запрос

//памяти под n указателей типа int*.

for(i=0; i<n; i++)

X[i]=new int[m]; // Идентификация указателя X[i] и запрос

// памяти под m указателей типа int.

for(i=0;i<n;i++)

for(j=0;j<m;j++)

ff>>X[i][j];

ff.close();

cout<<"Исходная целочисленная матрица матрица\n";

print_matrix(X,n,m);

cin.get();

return 0;

}

template <class pp> // Заголовок шаблонной функции

void print_matrix(pp **a,int n,int m) // можно записать в две строки.

{

int i,j;

for(i=0;i<n;i++)

{

for(j=0;j<m;j++)

{

cout.width(8);

int y=int(a[i][j] * 1000);

if(y % 10 > 5)

y=y/10+1;

else

{

if(y % 10 == 5 && y % 2!= 0)

y=y/10+1;

else

y/=10;

}

cout<<double(y) / 100;

}

cout<<'\n';

}

}

На рис. 9.2 представлен результат выполнения программы листинга 9.1.

Рис. 9.2. Результат работы программы листинга 9.1

Листинг 9.2. Пусть задана матрица A размером n × n. Необходимо построить матрицу B размером n × n, причем элементы матрицы определяются следующим образом: по индексам i и j строится область W, в которой . Область W показана на рис. 9.3 [26]. Индексы k и l изменяются в этом случае в следующих пределах: k от 0 до i, а l от j – i + k до j + i - k, причем при проведении сравнения с элементом akl следует проверять, что l лежит в диапазоне от 0 до n -1. Исходные данные находятся в файле “input.txt”, представленном на рис. 9.4.

Рис. 9.3. Вид области W для построения матрицы В

Содержимое файла “input.txt”

Рис. 9.4. Исходные данные для построения матрицы В

//L9_2.cpp

#include <fstream>

#include <iostream>

using namespace std;

double** bild_matr(double**, int); // Прототип функции bild_matr()

void print_matr(double**, int); // Прототип функции print_matr()

int main()

{

double **A, **B;

int i, j, n;

setlocale(LC_CTYPE, "russian");

ifstream fin("input.txt");

fin >> n;

A=new double *[n];

for(i=0;i<n;i++)

A[i]=new double[n];

for(i=0;i<n;i++)

for(j=0;j<n;j++)

fin>>A[i][j];

cout<<"Исходная матрица\n";

print_matr(A,n);

B=bild_matr(A,n);

cout<<"Полученная матрица\n";

print_matr(B,n);

cin.get();

return 0;

}

void print_matr(double**A, int n)

{

int i,j;

for(i=0;i<n;i++)

{

for(j=0;j<n;j++)

{

cout.width(5);

cout<<A[i][j];

}

cout<<'\n';

}

}

double** bild_matr(double**A, int n)

{

int i, j, k, l;

double **B;

B=new double*[n];

for(i=0;i<n;i++)

B[i]=new double[n];

for(i=0; i<n; i++)

for(j=0; j<n; j++)

{

B[i][j]=A[i][j];

for(k=0; k<=i; k++)

for(l=j-i+k;l<=j+i-k;l++)

if(l>=0 && l<n && B[i][j]<A[k][l])

B[i][j]=A[k][l];

}

return B;

}

Результат выполнения программы листинга 9.2 приведен на рис. 9.5.

Рис. 9.5. Результат работы программы листинга 9.2

Листинг 9.3. Пусть задан массив из 64 целых чисел. Будем считать, что одномерный массив состоит из целых чисел от 1 до 64. Построить матрицу размером 8 × 8 из данного одномерного массива, вставляя элементы одномерного массива в матрицу согласно схеме (рис. 9.6) [26].

Рис. 9.6. Схема размещения элементов одномерного массива в матрице

//L9_3.cpp

#include <iostream>

using namespace std;

int main()

{

int A[8][8], C[64];

int i, j, k, l=0; // Переменная l принимает значение 0 при

//движении по схеме на рис. 9.6 вниз и значение 1

//при движении вверх.

for(i=0;i<64;i++)

C[i]=i+1;

for(i=0;i<=7;i++)

{

if(i%2!=0)

for(k=0,j=7-i;k<=i;k++,j++)

{

A[k][j]=C[l];

l++;

}

else

for(k=i,j=7;k>=0;k--,j--)

{

A[k][j]=C[l];

l++;

}

}

for(i=1;i<=7;i++)

{

if(i%2!=0)

for(k=7,j=7-i;j>=0;k--,j--)

{

A[k][j]=C[l];

l++;

}

else

for(k=i,j=0;k<=7;k++,j++)

{

A[k][j]=C[l];

l++;

}

}

for(i=0; i<8; i++)

{

for(j=0; j<8; j++)

{

cout.width(4);

cout<<A[i][j];

}

cout<<'\n';

}

return 0;

}

Результат выполнения программы листинга 9.3 приведен на рис. 9.7.

Рис. 9.7. Результат работы программы листинга 9.3

Листинг 9.4. В программе создается квадратная единичная матрица, порядок которой вводится с клавиатуры. Память под элементы матрицы выделяется динамически во время выполнения программы. Динамически выделенная память освобождается оператором delete [24].

//L9_4.cpp

#include "stdafx.h"

#include <iostream>

#include <locale>

using namespace std;

void _tmain()

{setlocale (LC_ALL,"Russian");

int n;

int i, j;

cout<<"Введите порядок матрицы: \n";

cin>>n;

float **matr;

matr=new float *[n];

if(matr==NULL)

{cout<<"\n Не создан динамический массив";

return;

}

for(i=0; i<n; i++)

{matr[i]=new float [n];

if(matr[i]==NULL)

{cout<<"\n Не создан динамический массив";

return;

}

for(j=0; j<n; j++)

if(i!=j)

matr[i][j]=0;

else

matr[i][j]=1;

}

for(i=0; i<n; i++)

{cout<<"\n Строка "<<i+1<<":";

for(j=0; j<n; j++)

cout<<'\t'<<matr[i][j];

}

for(i=0; i<n; i++)

delete matr[i];

delete [] matr;

}

Результат выполнения программы листинга 9.4 представлен на рис. 9.8.

Рис. 9.8. Результат работы программы листинга 9.4

Листинг 9.5. В программе создается матрица, элементы которой задаются случайным образом. Память под элементы матрицы выделяется динамически во время выполнения программы. Программа состоит из трех функций: str() – функция вычисления среднего значения по строкам матрицы, stlb() – функция вычисления среднего значения по столбцам матрицы и функция _tmain().

//L9_5.cpp

#include "stdafx.h"

#include <stdio.h>

#include <locale>

#include <iostream>

#include <stdlib.h>

#include <conio.h>

using namespace std;

double* str (int** arr, int n, int m)

{

double* res = new double [n];

double k = 0;

for (int i = 0; i < n; i++)

{

for (int j = 0; j < m; j++)

{

k += arr[i][j];

}

res[i] = k / m;

k = 0;

}

return res;

}

double* stlb (int** arr, int n, int m)

{

double* res = new double [m];

double k = 0;

for (int j = 0; j < m; j++)

{

for (int i = 0; i < n; i++)

{

k += arr[i][j];

}

res[j] = k / n;

k = 0;

}

return res;

}

int _tmain()

{

setlocale(LC_ALL, "Russian");

int n, m;

cout << "Введите количество строк: ";

cin >> n;

cout << "\n";

cout << "Введите количество столбцов: ";

cin >> m;

cout << "\n";

int** arr;

arr = new int*[n];

for (int i = 0; i < n; i++)

{

arr[i] = new int[m];

}

for (int i = 0; i < n; i++)

{

for (int j = 0; j < m; j++)

{

arr[i][j] = rand() % 10;

}

}

cout<<"Матрица: \n"<<endl;

for (int i = 0; i < n; i++)

{

for (int j = 0; j < m; j++)

{

cout << arr[i][j];

cout << " ";

}

cout << "\n";

}

cout<<endl;

double* sr_stroki = str(arr, n, m);

cout << "Среднее значение по строкам: \n"<<endl;

for (int i = 0; i < n; i++)

{

cout << sr_stroki[i] << " ";

}

cout << '\n';

cout<<endl;

double* sr_stolb = stlb(arr, n, m);

cout << "Среднее значение по столбцам: \n"<<endl;

for (int i = 0; i < m; i++)

{

cout << sr_stolb[i] << " ";

}

cout << '\n';

return 0;

}

На рис. 9.9 представлен результат выполнения программы листинга 9.5.

Рис. 9.9. Результат работы программы листинга 9.5


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: