Динамические матрицы в C++
Динамическими в C++ могут быть не только одномерные массивы, но также и многомерные. Из тех, что входят в класс последних, рассмотрим двумерные динамические массивы (динамические матрицы). Ключевым объектом для работы с ними являются указатели.
Использование указателей для работы с динамическими матрицами
При работе с динамическими матрицами в C++ можно использовать обычные указатели. После описания указателя, необходимо будет выделить память для хранения NxM элементов (N — число строк, M — число столбцов). Так выделяется память для хранения целочисленной матрицы размером NxM:
int *A, n, m;
A=(int *) calloc (N*M, sizeof(int));
Для выделения памяти можно использовать также и функцию malloc:
A=(int *) malloc (N*M*sizeof(int));
или операцию new:
A=new int (N*M);
После выделения памяти, остается найти способ обратиться к элементу матрицы. Все элементы двумерного массива хранятся в одномерном массиве размером NxM элементов. Сначала в этом массиве расположена 0-я строка матрицы, затем 1-я и т. д. Поэтому для обращения к элементу Ai, j необходимо по номеру строки i и номеру столбца j вычислить номер элемента k в динамическом массиве. Учитывая, что в массиве элементы нумеруются с нуля k = iM + j, обращение к элементу A[i] [j] будет таким *(A + i*m+j).
В качестве примера работы с динамическими матрицами рассмотрим задачу.
Задача
Заданы две матрицы матрицы вещественных чисел A(N, M) и B(N, M). Вычислить матрицу C = A + B.
Решение
Как известно, суммой матриц одинаковой размерности называется матрица, элементы которой получаются сложением соответствующих элементов исходных матриц. Рассмотрим блок-схему алгоритма сложения матриц.
Код программы сложения матриц:
#include "stdafx.h"
#include <iostream>
using namespace std;
int main()
{
setlocale (LC_ALL, "RUS");
int i, j, N, M; double *a,*b,*c;
//ввод размеров матрицы
cout<<"N = "; cin>>N;
cout<<"M = "; cin>>M;
//выделение памяти для матриц
a=new double[N*M];
b=new double[N*M];
c=new double[N*M];
//ввод матрицы А
cout<<"введите матрицу А"<< endl;
for (i=0; i < N; i++)
for (j=0; j < M; j++)
{
cin>>*(a+i*M+j);
}
//ввод матрицы B
cout<<"введите матрицу B"<< endl;
for (i=0; i < N; i++)
for (j=0; j < M; j++)
{
cin>>*(b+i*M+j);
}
//вычисление матрицы C=A+B
for (i=0; i < N; i++)
for (j=0; j < M; j++)
*(c+i*M+j)=*(a+i*M+j)+*(b+i*M+j);
//ввод матрицы С
cout<<"матрица С:"<< endl;
for (i=0; i < N; cout<< endl, i++)
for (j=0; j < M; j++)
cout<<*(c+i*M+j)<<"\t";
//освобождение памяти
delete []a;
delete []b;
delete []c;
system("pause");
return 0;
}
Использование двойных указателей для работы с динамическими матрицами
Основной способ работы с динамическими матрицами базируется на использовании двойных указателей. Рассмотрим следующий фрагмент программы.
int main()
{
int N, M;
float **a;
a=new float *[N];
}
С помощью оператора new создан массив из N элементов, каждый из которых является адресом, где хранится указатель на float. Осталось определить значение этого указателя. Для этого организуем цикл от 0 до N-1, в котором каждый указатель будет адресовать участок памяти, где хранится M элементов типа float.
for (i=0; i < N; i++)
a[i]=new float [M];
После этого определен массив N указателей, каждый из которых адресует массив из M вещественных чисел (типа float). Фактически создана динамическая матрица размера NxM. Обращение к элементу динамической матрицы проходит так же, как и к элементу статической матрицы. Для обращение к элементу ai, j в программе на C++ необходимо указать ее имя, и в квадратных скобках номер строки и столбца (a[i] [j]).
Задача 2
Написать программу умножения двух матриц вещественных чисел A(N, M) и A(M, L).
Решение 2
Программа перемножения двух таких матриц, реализованных при помощи двойных указателей, будет выглядеть так:
#include "stdafx.h"
#include <iostream>
using namespace std;
int main()
{
setlocale (LC_ALL, "RUS");
int i, j, k, N, M, L;
//описание двойных указателей для матриц A, B, С
double **a,**b,**c;
//ввод размерности матриц
cout<<"N = "; cin>>N;
cout<<"M = "; cin>>M;
cout<<"L = "; cin>>L;
//выделение памяти для массива а, каждый элемент массива -
//указатель на double
a=new double *[N];
for (i=0; i < N; i++)
//выделение памяти для каждого элемента
//a[i], a[i] адресует М элементов типа double
a[i]=new double [M];
//выделение памяти для массива b, каждый элемент массива -
//указатель на double
b=new double *[M];
for (i=0; i < M; i++)
//выделение памяти для каждого элемента
//b[i], b[i] адресует М элементов типа double
b[i]=new double [L];
//выделение памяти для массива c, каждый элемент массива -
//указатель на double
c=new double *[N];
for (i=0; i < N; i++)
//выделение памяти для каждого элемента
//c[i], c[i] адресует L элементов типа double
c[i]=new double [L];
//ввод матриц А и В
cout<<"введите матрицу А"<< endl;
for (i=0; i < N; i++)
for (j=0; j < M; j++)
cin>>a[i][j];
cout<<"введите матрицу B"<< endl;
for (i=0; i < M; i++)
for (j=0; j < L; j++)
cin>>b[i][j];
//умножение матриц A и B
for (i=0; i < N; i++)
for (j=0; j < L; j++)
//цикл для умножения i-й строки матрицы А на j-й столбец матрицы В
for (c[i][j]=0, k=0; k < M; k++)
c[i][j]+=a[i][k]*b[k][j];
//вывод матрицы С
cout<<"Матрица С "<< endl;
for (i=0; i < N; cout<< endl, i++)
for (j=0; j < L; j++)
cout<< c[i][j]<<"\t";
for (i=0; i < N; i++)
//освобождение памяти для каждого элемнта a[i]
delete [] a[i];
//освобождение памяти для а
delete []a;
for (i=0; i < M; i++)
//освобождение памяти для каждого элемнта b[i]
delete [] b[i];
//освобождение памяти для b
delete [] b;
for (i=0; i < N; i++)
//освобождение памяти для каждого элемнта c[i]
delete [] c[i];
//освобождение памяти c
delete []c;
system("pause");
return 0;
}