Есть задачи, в которых требуется обработать элементы главной или побочной диагонали квадратной матрицы, объявленной, например, так: const n=5; int A[n][n]; Структура циклов останется такой же, как при решении аналогичной задачи для одномерного массива. Например, для нахождения среднего значения главной диагонали необязательно писать два следующих вложенных цикла:
float Sum=0;
for (int i=0; i<n; i++)
for (int j=0; j< n; j++)
if ( i==j)Sum+=A[i][j];
Sum/=n;
Так как для элементов главной диагонали оба индекса одинаковы, то это можно выполнить компактнее с помощью одного цикла:
float Sum=0;
for (int i=0; i<n; i++)
Sum+=A[i][i];
Sum/=n;
Сравните с задачей нахождения этого же параметра в одномерном массиве.
Для обработки побочной диагонали, как и при решении некоторых других типов задач, необходимо найти зависимость второго индекса от первого. Легко видеть, что сумма индексов равна n-1. Поэтому второй индекс будет равен n-1-i, и соответствующая часть программы будет такой:
float Sum=0;
for (int i=0; i<n; i++)
Sum+=A[i][ n-1-i];
Sum/=n;
Верхний треугольник квадратной матрицы относительно главной диагонали — это те элементы, у которых i<j, если главная диагональ не включается, или i<=j, если включается. Аналогично определяется нижний треугольник относительно главной диагонали и треугольники относительно побочной диагонали.
Для обработки таких треугольников необходимо определить, как изменяются индексы. Анализируя, например, верхний треугольник, можно видеть, что в нулевой строке j изменяется от 0 до n-1, в первой строке — от 1 до n-1, во второй строке — от 2 до n-1 и так далее. Значит, в произвольной i-й строке индекс j изменяется от i до n-1. Поэтому, например, подсчёт количества нулевых элементов верхнего треугольника, включая и главную диагональ, будет выглядеть следующим образом:
int K0=0;
for (int i=0; i<n; i++)
for (int j=i; j< n; j++)
if (A[i][j] ==0) K0++;
Если диагональные элементы не надо анализировать, то заголовок внутреннего цикла будет таким:
for (int j=i+1; j< n; j++)…
Упражнение. Эту же задачу решить для нижнего (верхнего) треугольника относительно побочной диагонали.
3.5. Преобразование матрицы
Перестановка двух строк, номера n1 и n2 которых заданы, выполняется следующим образом. Составим функцию для перестановки двух целых чисел:
void RR( int &x, int &y)
{ int t; t=x; x=y; y=t;}
В другой функции или в main выполняем поэлементную перестановку каждой пары элементов:
for (int j=0; j<m; j++)
RR( A[n1][ j] , A[n2][j]);
В качестве упражнения с помощью той же функции выполните перестановку m1–го и m2–го столбцов, если m1 и m2 заданы.
Удаление k–й строки, где k известно, выполняется так:
for (int i=k; i<n-1; i++)
for (int j=0; j<m; j++)
A[i][j]=A[i+1][j];
Здесь на место k–й строки помещаем каждый элемент (k+1)–й строки, на место (k+1)–й — (к+2)–ю строку и так далее. Наконец, на место (n-2)–й копируем (n-1)–ю строку. Таким образом, все строки, начиная с (к+1)–й, “поднимаем на одну вверх”. При этом объём зарезервированной памяти для матрицы не изменяется. По–прежнему в памяти находится n строк, то есть физически ни одну строку из памяти мы не удаляли. Но после удаления одной строки количество обрабатываемых строк на одну уменьшается. Последняя строка в обработке уже не должна участвовать.
Для вставки одной строки после к-й на первом этапе необходимо все строки с (n-1)–й до (к+1) в обратном порядке “опустить вниз”:
for (int i=n-2; i>=k+1; i - -)
for (int j=0; j<m; j++)
A[i+1][j]=A[i][j];
Затем на место освободившейся (k+1)–й строки надо поместить вставляемую строку, например, одномерный массив B такой же размерности m, что и строка матрицы:
for (int j=0; j<m; j++)
A[k+1][j]=B[j];
При объявлении матрицы необходимо учесть, что после вставки количество строк увеличится. Поэтому если по условию вставляется одна строка, то объявляем так: int A[n+1][m]. Если после каждой строки с некоторым условием (например, в строке больше половины нулей) надо вставить новую строку, то матрицу надо объявить так: int A[2*n][m]. В этом случае резервируется максимальный объём памяти в предположении, что после каждой строки надо вставлять новую. Реально такой вариант будет маловероятным и память будет использоваться неэффективно.
Похожая проблема с памятью имеет место и при удалении строк. Более того, если перестановку, удаление или вставку строк надо выполнять несколько раз, то для больших матриц может возникнуть проблема и с временем выполнения программы. Поэтому на практике такое преобразование эффективнее выполнять с помощью динамических матриц или списков (2–й семестр).