Лабораторная работа №9
Матрицы (двумерные массивы)
Цель работы: программирование алгоритмов обработки двумерных массивов
Основные сведения
Матрица – это прямоугольная таблица элементов (например, чисел или символов). Матрица представляется в виде двумерного массива, то есть массива, все элементы которого имеют два индекса. Матрица, как и таблица, состоит из строк и столбцов. Два индекса элемента - это и есть номера строки и столбца, на пересечении которых этот элемент находится. В языке Си каждый индекс записывается отдельно в квадратных скобках. Каждую строку и каждый столбец матрицы можно рассматривать как обычный одномерный массив. Поэтому можно сказать, что матрица – это массив из массивов.
Первый индекс элемента матрицы – это строка, второй – столбец. Поэтому когда говорят о «матрице 4 на 5», это означает, что матрица имеет 4 строки и 5 столбцов. Матрицы, у которых число строк равно числу столбцов, называют квадратными. В квадратных матрицах можно выделить главную диагональ – это все элементы, у которых номер строки равен номеру столбца, то есть A[0][0], A[1][1],..., A[N-1][N-1] для матрицы размером N на N.
Объявление матриц
Матрицы объявляются так же, как и простые массивы, но у них не один индекс, а два. При объявлении в отдельных квадратных скобках указывается количество строк и количество столбцов. Например, оператор
int B[10][10];
выделит место в памяти под матрицу целых чисел, имеющую 10 строк и 10 столбцов. Если матрица глобальная (объявляется выше всех процедур и функций), то она в самом начале заполняется нулями. Локальные матрицы (объявленные внутри процедуры или функции) первоначально содержат «мусор» – неизвестные значения.
Начальные значения элементов
При объявлении можно сразу задать все или часть ее элементов, например:
float X[2][3] = {{1., 2., 3.},{4., 5., 6.}};
Как видно из примера, элементы каждой строки заключаются в отдельные фигурные скобки. Если задать не все элементы, то остальные заполнятся нулями:
float X[2][3] = {{1., 3.},{6.}};
Здесь элементы X[1][2], X[2][1] и X[2][2] будут нулевыми.
Расположение матриц в памяти
Во всех современных языках программирования элементы матрицы располагаются по строкам, то есть сначала изменяется последний индекс. Объявленная выше матрица X расположена так:
X[0][0] X[0][1] X[0][2] X[1][0] X[1][1] X[1][2]
Стандартный ввод и вывод
Для работы с матрицами требуется вложенный цикл, то есть цикл в цикле.
#include <stdio.h>
const int M = 5; // число строк
const int N = 4; // число столбцов
main()
{
int i, j, A[M][N];
for (i = 0; i < M; i ++) // цикл по строкам
for (j = 0; j < N; j ++) // цикл по столбцам строки (элементы строки)
{
printf ("A[%d][%d]=", i, j); // подсказка для ввода
scanf ("%d", & A[i][j]); // ввод A[i][j]
}
// работа с матрицей
}
Заполнение случайными числами
Выполняется также в двойном цикле аналогично одномерным массивам. В примере показано заполнение целой матрицы случайными числами в интервале [a,b].
for (i = 0; i < M; i ++)
for (j = 0; j < N; j ++)
A[i][j] = random(b-a+1) + a;
Вывод на экран
При выводе матрицы ее элементы желательно расположить в привычном виде – по строкам, т.е. вывели одну строку матрицы, перешли на новую строку экрана, и т.д. Надо учитывать, что для красивого вывода на каждый элемент матрицы надо отвести равное количество символов (иначе столбцы будут неровные). Делается это с помощью форматирования – цифра после знака процента задает количество символов, отводимое на данное число.
printf("Матрица A\n");
for (i = 0; i < M; i ++) // цикл по строкам
{
for (j = 0; j < N; j ++) // вывод одной строки (в цикле)
printf ("%4d", A[i][j]); // 4 символа на число
printf("\n"); // переход на другую строку
}
Алгоритмы для работы с матрицами
Поиск минимального элемента
В отличие от одномерных массивов, для перебора всех элементов матрицы надо использовать двойной цикл. Ниже показано, как найти минимальный элемент в массиве и его индексы. Сначала считаем, что минимальным является элемент A[0][0], а затем проходим все элементы, проверяя, нет ли где еще меньшего. Можно запоминать только индексы, а значение минимального элемента получать прямо из массива.
float A[M][N], i, j, row, col;
...
row = col = 0; // сначала считаем, что A[0][0] - минимальный
for (i = 0; i < M; i ++) // просмотр всех строк
for (j = 0; j < N; j ++) // просмотр всех столбцов
if (A[i][j] < A[row][col])
{
row = i; // запомнили новые индексы
col = j;
}
printf ("Минимальный элемент A[%d][%d]=%d",row, col, A[row][col]);
Работа с отдельными элементами
Рассмотрим квадратную матрицу N на N. Выведем на экран обе ее диагонали (главную диагональ и перпендикулярную ей). С главной диагональю все просто – в цикле выводим все элементы, у которых номера строки и столбца равны, то есть A[i][i] для всех i от 0 до N-1.
Вторую диагональ формируют такие элементы:
A[0][N-1], A[1][N-2], A[2][N-3],..., A[N-1][0]
Обратим внимание, что каждый следующий элемент имеет номер строки на 1 больше, а номер столбца – на 1 меньше. Таким образом, сумма номеров строки и столбца постоянна и равна N-1. Тогда, зная номер строки i можно сразу сказать, что на второй диагонали стоит ее элемент A[i][N-1-i].