Цель лабораторной работы: изучить программировани задач, в которых требуется использовать такую структуру данных как двумерные массивы (матрицы). В этой лабораторной работе предполагается программирование статических матриц.
Теоретические сведения
Двумерные массивы – матрицы – представляют собой массивы одномерных массивов (таблицы) и задаются двумя числами в квадратных скобках:
тип_элементов имя_массива [размер1] [размер2];
Здесь размер1 – количество строк, размер2 – количество столбцов.
Пример - объявление матриц
double matr1 [100] [10];
int matr2 [10] [20];
В памяти компьютера матрицы занимают последовательно расположенные ячейки в следующем порядке: сначала располагается первая строка, за ней – вторая, третья и так далее.
Заполнение и обработку многомерных массивов обычно производят, пользуясь вложенными циклами. При этом медленнее всего изменяется крайний левый индекс, а быстрее всего – крайний правый.
Пример – ввод целочисленной матрицы с клавиатуры
#include <iostream>
const ROW = 5;
const COL = 4;
int main ( )
{ int i, j;
int x [ROW][COL];
for (i = 0; i < ROW; i++) // по строкам
{ for (j = 0; j < COL; j++) // столбцам
{ cout << “x[“ << i << “][“ <<j <<”]”;
cin >> x[i][j];
}
}
return 0;
}
Пример – ввод целочисленной матрицы с помощью генератора случайных чисел
#include <iostream>
#include <iomanip.h>
#include <stdlib.h>
const ROW = 5;
const COL = 4;
int main ( )
{ int i, j;
int x [ROW][COL];
for (i = 0; i < ROW; i++) // по строкам
{ for (j = 0; j < COL; j++) // столбцам
{ x[i][j] = rand ( ) % 10 – 5;
cout << setw (4) <<x[i] [j];
}
cout << endl;
}
return 0;
}
Вывод матриц тоже происходит с помощью вложенных циклов.
for (i = 0; i < ROW; i++)
{ for (j = 0; j < COL; j++)
cout << setw(4) << x[i][j];
cout << endl;
}
Инициализация многомерных массивов осуществляется аналогично инициализации одномерных массивов. При этом инициализирующие значения должны совпадать с последовательностью хранения элементов массива в памяти.
int x [5] [3] = { {1, 2, 3), // строка первая
{4, 5, 6}, // строка вторая
{7, 8, 9}, // строка третья
{10, 11, 12}, // строка четвертая
{13, 14, 15} }; // строка пятая
Типичной ошибкой, не вызывающей сообщения компилятора, является объявление вида:
int m [i, j]; // ошибка
Компилятор воспринимает запятую как операцию “запятая” и игнорирует один из индексов.
Обрабатывая матрицы, часто приходится решать задачи одного из следующих классов:
- работа с матрицей в целом,
- работа со строками или столбцами матрицы,
- работа с диагональными элементами матрицы.
При работе с матрицей в целом вся подготовительная и инициализирующая часть выполняется один раз перед внешним циклом.
Пример – поиск максимального элемента матрицы
…
int matr [n] [k], max;
…
max = matr [0][0];
for (i = 0; i < n; i++)
for (j = 0; j < k; j++)
if (max < matr [i][j]) max = matr [i][j];
…
При работе со строками матрицы инициализирующие действия производятся внутри внешнего цикла и до начала внутреннего цикла.
Пример – поиск максимальных элементов каждой строки матрицы
…
int matr [n] [k];
int max [n];
…
for (i = 0; i < n; i++)
{ max[i] = matr [i][0];
for (j = 0; j < k; j++)
if (max[i] < matr [i][j]) max[i] = matr [i][j];
}
…
В результате этих действий формируется столбец (одномерный массив), размерность которого равна числу строк в обрабатываемой матрице.
Работа со столбцами матрицы отличается от работы со строками только тем, что цикл обработки столбцов становится внешним и результирующий массив (строка) имеет размерность, равную количеству столбцов.
Пример – поиск максимальных элементов каждого столбца матрицы
…
int matr [n] [k];
int max [k];
…
for (j = 0; j < k; i++)
{ max[j] = matr [0][j];
for (i = 0; i < n; i++)
if (max[j] < matr [i][j]) max[j] = matr [i][j];
}
…
При работе с диагональными элементами матрицы предполагают, что матрица квадратная.
a00 a01… a04
a10 a11… a14
…
а40 a41… a44
Диагональ, соединяющая левый верхний угол матрицы с ее правым нижним углом, называется главной, а соединяющая правый верхний угол с левым нижним – побочной.
Для элементов, стоящих на главной диагонали, выполняется равенство i = j. Если выполняется условие i > j, то элемент находится под главной диагональю, если i < j, то элемент находится над главной диагональю.
Элемент находится на побочной диагонали, если выполняется условие i = n – j – 1. Здесь n – порядок (количество элементов) матрицы.
i > (n – j – 1) – условие нахождения элемента под побочной диагональю.
i < (n – j – 1) – условие нахождения элемента над побочной диагональю.
Пример
Найти среднее арифметическое отрицательных элементов, расположенных под главной диагональю квадратной действительной матрицы 9×9
#include <iostream>
#include <iomanip.h>
#include <stdlib.h>
const ROW = 9;
const COL = 9;
int main ( )
{ int i, j, n = 0;
float matr [ROW][COL];
float srednee = 0;
for (i = 0; i < ROW; i++) // по строкам
{ for (j = 0; j < COL; j++) // столбцам
{ matr[i][j] = (float) rand ( ) % 20 – 10;
cout << setw (6) <<matr[i] [j];
}
cout << endl;
}
for (i = 0; i < ROW; i++) // по строкам
{ for (j = 0; j < i; j++)
if (matr[i][j] < 0)
{ n++;
srednee += matr[i][j];
}
srednee = srednee / n;
cout << endl;
cout << “Среднее арифметическое = “ << srednee << endl;
return 0;
}
Примеры программ со статическими матрицами
Пример 1
Найти сумму элементов матрицы, лежащих выше главной диагонали.
Алгоритм решения этой задачи следующий. Вводим переменную для хранения суммы, обнуляем ее предварительно. Организовываем цикл в цикле (внешний по строкам, внутренний по столбцам), просматриваем каждый элемент матрицы, но суммируем только те элементы матрицы, которые лежат выше главной диагонали (для индексов справедливо условие i < j).
#include <iostream>
using namespace std ;
int main ( )
{
int i , j , n;
int a [ 20 ] [ 20 ] ; // описание матрицы
cout <<" n = ";
cin >> n; //ввод количества строк и столбцов
cout <<"Ввод матрицы a "<< endl ;
for ( i =0; i<n; i++) // цикл по строкам
for ( j =0; j<m; j++) // цикл по элементам строки
cin >> a [ i ] [ j ] ;
// работа с матрицей
int s = 0;
for ( i =0; i<n ; i++)
for ( j =0; j < n; j++)
// если элемент лежит выше главной диагонали, то наращиваем сумму
i f ( j > i ) s+=a [ i ] [ j ] ;
cout<<" S = "<<s<<endl ;
return 0;
}
Пример 2
Вычислить количество положительных элементов квадратной матрицы, расположенных по ее периметру и на диагоналях.
Нам не нужно рассматривать всю матрицу, достаточно рассмотреть ее первую строку, последнюю строку, первый столбец, последний столбец, главную диагональ и побочную диагональ.
Будем считать, что матрица a имеет размер [n*n].
Элементы первой строки матрицы a можно представить как a[0][ i], где i меняется от 0 до n,
элементы последней строки - a[ n-1, 0],
элементы первого столбца – a[ i, 0].
элементы последнего столбца – a[ i, n-1],
элементы главной диагонали – a[ i, i],
элементы побочной диагонали – a[ i, n- i -1]
При подсчете надо иметь ввиду, что некоторые элементы строк и столбцов матрицы могут просматриваться дважды и исключить такую возможность. Если размер матрицы n – нечетное число, то главная и побочная диагонали пересекаются, тогда элемент пересечения будет просматриваться дважды, это тоже надо учесть.
#include <iostream>
using namespace std ;
int main ( )
{
int i , j , n, k;
int a [ 20 ] [ 20 ] ; // описание матрицы
cout <<" n = " ;
cin >> n; //ввод количества строк и столбцов
cout <<"Ввод матрицы a "<< endl ;
for ( i =0; i<n; i++) // цикл по строкам
for ( j =0; j<n; j++) // цикл по элементам строки
cin >> a [ i ] [ j ] ;
//k - количество положительных элементов матрицы,
// расположенных по её периметру и на диагоналях.
for ( i=0, k=0; i<n; i++)
{
if (a [ i ] [ i ] > 0) k = k+1; // элемент лежит на главной диагонали
if (a [ i ] [n−i −1] > 0) k = k+1; // элемент лежит на побочной диагонали
}
for ( i =1; i<n−1; i++)
{
if (a [ 0 ] [ i ] > 0) k = k+1; // элемент находится в нулевой строке
if (a [n−1] [ i ] > 0) k++; // элемент находится в последней строке
if (a [ i ] [ 0 ] > 0 ) k++; // элемент находится в нулевом столбце
if (a [ i ] [n−1] > 0) k++; // элемент находится в последнем столбце
}
// элемент, находящийся на пересечении диагоналей, возможно, подсчитан дважды,
// надо уменьшить вычисленное значение k на один
if ( (n%2 != 0) && (a [n/ 2] [n/2] > 0) ) k = k-1;
cout<<" k = "<<k<<endl ;
return 0;
}
Пример 3
Преобразовать исходную матрицу так, чтобы на первом месте в каждой строке стояло среднее арифметическое элементов этой строки.
Для решения задачи нужно найти в каждой строке матрицы сумму элементов и разделить ее на количество элементов в строке. Затем полученное число записать в нулевой элемент соответствующей строки.
#include <iostream>
#include <iomanip> // библиотека манипуляторов
using namespace std ;
int main ( )
{
int i , j , n, m;
float a [ 20 ] [ 20 ] ; // описание матрицы
cout <<" n = " ;
cin >> n; //ввод количества строк
cout << " m = " ;
cin >> m; //ввод количества столбцов
cout <<"Ввод матрицы a "<< endl ;
for ( i =0; i<n; i++) // цикл по строкам
for ( j =0; j<m; j++) // цикл по столбцам
cin >> a [ i ] [ j ] ;
// работа с матрицей
float S = 0;
for ( i =0; i<n; i++) // цикл по строкам
{
for ( j =0; j<m; j++) // цикл по столбцам
S = S + a[ i ] [ j ] ;
// когда строка просмотрена, надо найти среднее арифметическое и записать его в начало строки
a[ i ] [ 0 ] = S / m;
// переходим на новую строку (новая итерация внешнего цикла)
}
// преобразованная матрица
for ( i =0; i<n; i++) // цикл по переменной i, перебираем строки матрицы
{
for ( j =0; j<m; j++) // цикл по переменной j, перебираем элементы внутри строки
cout << setw(5) << a [ i ] [ j ] ; // вывод очередного элемента матрицы
cout<<endl ; // после вывода всех элементов строки переходим на новую строку
}
return 0;
}
Пример 4
Поменять местами минимальный и максимальный элемент в матрице.
Для решения этой задачи надо найти минимальный элемент матрицы (min) и его индексы imin и jmin, а также максимальный элемент (max) и его индексы imax и jmax. Затем надо поменять местами элементы a[ imin ][ jmin ] и a[ imax ][ jmax ], для этого надо ввести вспомогательную переменную.
Чтобы найти минимум во всей матрице, в переменную min запишем значение a[0][0], в переменную imin и в переменную jmin (номер строки и столбца, где находится минимальный элемент) запишем нули. Затем в двойном цикле сравниваем каждый элемент матрицы с минимальным (переменная min). Если какой-то элемент окажется меньше, чем min, записываем его в переменную min, а в переменную imin – текущее значение индекса i, в переменную jmin – текущее значение индекса j. Поиск максимального элемента матрицы аналогичен, только сравнение будет другое.
#include <iostream>
#include <iomanip> // библиотека манипуляторов
using namespace std ;
int main ( )
{
int i , j , n, m;
int a [ 20 ] [ 20 ] ; // описание матрицы
cout <<" n = " ;
cin >> n; //ввод количества строк
cout << " m = " ;
cin >> m; //ввод количества столбцов
cout <<"Ввод матрицы a "<< endl ;
for ( i =0; i<n; i++) // цикл по строкам
for ( j =0; j<m; j++) // цикл по столбцам
cin >> a [ i ] [ j ] ;
// работа с матрицей
int min, max, imin. imax, jmin, jmax;
min = a[0][0]; max = a[0][0];
imin = 0; jmin = 0;
imax =0; jmax = 0;
for ( i =0; i<n; i++) // цикл по строкам
for ( j =0; j<m; j++) // цикл по столбцам
{ if (a[i][j] < min)
{ min = a[i][j];
imin = i;
jmin = j;
}
if (a[i][j] > max)
{ max = a[i][j];
imax = i;
jmax = j;
}
}
// меняем местами
int b;
b = a[ ima][jmax];
a[ imax ][ jmax ] = a[ imin ][jmin ];
a[imin][jmin] = b;
// преобразованная матрица
for ( i =0; i<n; i++) // цикл по переменной i, перебираем строки матрицы
{
for ( j =0; j<m; j++) // цикл по переменной j, перебираем элементы внутри строки
cout << setw(5) << a [ i ] [ j ] ; // вывод очередного элемента матрицы
cout<<endl ; // после вывода всех элементов строки переходим на новую строку
}
return 0;
}
Пример 5
Проверить, является ли заданная матрица единичной.
Квадратная матрица называется единичной, если по ее главной диагонали записаны единицы, а все остальные элементы матрицы нулевые.
Чтобы решить задачу, предположим, что матрица является единичной. Если окажется, что какой-то элемент главной диагонали не равен 1 или какой-то элемент помимо диагональных является ненулевым, то матрица единичной не будет.
#include <iostream>
using namespace std ;
int main ( )
{
int i , j , n;
int a [ 20 ] [ 20 ] ; // описание матрицы
cout <<" n = ";
cin >> n; //ввод количества строк и столбцов
cout <<"Ввод матрицы a "<< endl ;
for ( i =0; i<n; i++) // цикл по строкам
for ( j =0; j<m; j++) // цикл по элементам строки
cin >> a [ i ] [ j ] ;
// предположим, что матрица единичная и запишем в некоторой переменной pr единицу.
// Если значение этой переменной не изменится по выходу из цикла, то матрица единичная
int pr =1;
for ( i =0; i<n; i++) // цикл по строкам
for ( j =0; j<n; j++) // цикл по элементам строки
if ((( i == j) && (a[i][j] != 1)) || ((i != j) && (a[i][j] != 0)))
{ pr = 0;
break; // матрица не является единичной, выходим из цикла
}
if (pr == 1)
cout << “Матрица является единичной”;
else cout << “Матрица единичной не является”;
return 0;
}
Порядок выполнения работы
Построить алгоритм решения задачи и написать программу согласно вариантам заданий.
Контрольные вопросы
1. Как объявить матрицу в программе на С++?
2. Как индексируются элементы матрицы в языке С++?
3. Что такое главная и побочная диагонали в матрице?
4. Каким образом можно объявить трехмерный массив в С++ программе?
Содержание отчета
1. Титульный лист отчета
2. Запись алгоритма решения задачи
3. Текст программы на языке С++
4. Скриншоты результатов, выводимых на экран для заранее подготовленных тестовых примеров для задачи
Дата: 2019-04-23, просмотров: 196.