Введение

Линейные алгоритмы

Алгоритмы с ветвлением

Алгоритмы с повторением

Одномерный массив (вектор)

Двумерный массив (матрица)

маркированный список

справочные материалы

маркированный список

теоретические вопросы

маркированный список

задачи, решения, программы

Пользовательские процедуры и функции

Строки

Множества

Записи

Файлы

Графика

На главную
              

Двухмерные  массивы

Многомерные массивы отличаются от одномерных количеством индексов. В двумерных их два, в трехмерных - три и т.д. Таким образом появляется возможность различать элементы массива не по одному признаку, а по нескольким. Например, возьмем матрицу:

1 2 3 4
5 6 7 8
3 4 5 6

Каждая ее строка - это массив из 4-х целых чисел. Но все строки также образуют массив из 3-х элементов (то есть строк). Таким образом, каждый элемент матрицы определяется номером массива-строки, где он находится, и номером в этой строке, т.е. двумя номерами (иначе говоря, индексами).

I. Объявление многомерных массивов.

По правилам Паскаля матрицу можно объявить так:
Сначала объявить тип "строка матрицы" (из целых чисел):

type mat_string = array [1..4] of integer;
А затем на его основе - тип "массив строк":
type matritsa = array [1..3] of mat_string;
Впрочем, это можно записать короче:
type matritsa = array [1..3] of array [1..4] of integer;
Или еще короче:
type matritsa = array [1..3,1..4] of integer;
Аналогично можно описать массивы с тремя индексами, четырьмя и т.д.
Общий синтаксис таков:
array [<тип 1-го индекса>, <тип 2-го индекса>, ...] of <тип элементов>;

<Типов индекса> может быть до семи. При этом они могут иметь различный вид (не обязательно числа). Например, можно объявить такой трехмерный массив:

type mas3d = array[1..10,'a'..'z', boolean] of real;
Здесь первым индексом будет номер, вторым - маленькая латинская буква, а третьим - false или true, значения типа boolean.
 

II. Работа с индексами в многомерных массивах.
 

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

var M: matritsa;
то ее элемент, расположенный во 2-ой строке на 3-ем месте, будет иметь имя A[2][3].

Можно представить себе двумерный массив как "массив, состоящий из массивов". Тогда первый индекс элемента воспринимается как номер (индекс) массива - составляющего, а второй - номер (индекс) элемента из него.
Наглядно:


Замечание. Имя  означает A[2] в приведенном примере. Это вся вторая строка матрицы целиком. Именно поэтому необходимо добавить еще [3], чтобы выбрать в ней элемент.

В двумерном массиве индексы изменяются так:

a[1,1] a[1,2] a[1,3] a[1,4] ... a[1, n]
a[2,1] a[2,2] a[2,3] a[2,4] ... a[2, n]
a[3,1] a[3,2] a[3,3] a[3,4] ... a[3, n]
a[4,1] a[4,2] a[4,3] a[4,4] ... a[4, n]
..............................................................
a[m,1] a[m,2] a[m,3] a[m,4] ... a[m, n]
Здесь m - число строк в массиве, а n - число столбцов.
Итак, первый индекс - номер строки, второй - номер столбца. Если перебирать элементы массива от начала к концу, то можно заметить, что второй индекс изменяется быстрее (тоже самое в трех- и более мерных массивах: последний индекс изменяется быстрее всех, предпоследний быстрее всех, кроме последнего и т.д.). Поэтому при переборе всех элементов массива внутренний цикл (который выполняется быстрее всего) пишут по последнему индексу, а внешний - по первому.

Важно научиться находить закономерности в изменении индексов. Работа с массивами, как правило, требует применения циклов, и, значит, поиска формул изменения индексов. В этом деле необходимы практика и наблюдательность. Впрочем, можно привести несколько советов и примеров.
Скажем, как описать "все элементы 3-ей строки"? Посмотрите на таблицу распределения индексов. Первый индекс - номер строки, он равен 3. Второй - номер столбца, он изменяется от 1 (первый элемент строки) до n (последний). Значит, перебрать все элементы 3-ей строки можно с помощью цикла

for j := 1 to n do {какие-то действия с элементом a[3,j]}
А вот формула изменения индексов для второго столбца: a[i,2], где i
изменяется от 1 до m. Соответствующий цикл:
for i := 1 to m do {какие-то действия с элементом a[i,2]}
Пример посложнее: что-то сделать со всеми элементами массива, которые лежат ниже главной диагонали (включая саму диагональ). Посмотрите на элементы главной диагонали. Для них характерно то, что оба индекса у них одинаковые. А элементы ниже ее? У них первый индекс больше второго.
Однако не спешите писать так:
for i := 1 to m do
for j := 1 to n do
if (i >= j) then {какие-то действия с элементом a[i,j]}

Можно сделать элегантнее. Возьмем первую строку. Из нее условию удовлетворяет только первый элемент. Вторую: первый и второй. Третью: первые три. Значит, из каждой строки нужно брать i первых элементов, считая, что i - номер строки. Получим такие циклы:
for i := 1 to m do
for j := 1 to i do
{какие-то действия с элементом a[i,j]}

Так можно "распотрошить" любую задачу на двумерные массивы. Не нужно забывать, что тип переменной цикла должен совпадать с типом индекса, который она заменяет.
Еще одно замечание. Парные циклы, приведенные в последнем примере, называются вложенными (потому что они вкладываются друг в друга как матрешки). Исполняются они так. Сначала переменная внешнего цикла получает первое значение, затем внутренний цикл выполняется ЦЕЛИКОМ, от первого значения своей переменной до последнего. Затем переменная внешнего получает второе значение и внутренний цикл опять выполняется целиком. И так далее.
 

III. Ввод и вывод многомерных массивов.
 

Как и в случае одномерных, многомерные массивы нельзя ввести (и вывести) целиком, одним оператором. Более того, одним циклом уже не обойдешься. Общее правило таково: перебрать все элементы массива и каждый вести отдельно. Это требует столько же вложенных циклов, сколько индексов у массива. Итак, ввод массива

var A: array [1..5,1..5] of integer;
осуществляется, например, так:

for i := 1 to 5 do
for j := 1 to 5 do
begin
write('a[', i, '][', j, ']=');
readln(a[i, j]);
end;

Есть более красивый способ для двумерных массивов (он требует подключения модуля crt):
for i := 1 to 5 do
for j := 1 to 5 do
begin
gotoxy(X+j*5, Y+i);
readln(a[i, j]);
end;

Здесь X и Y - некие числа-константы (не переменные). При таком способе вводимые элементы располагаются "квадратом". X и Y задают расположение его левого верхнего угла (X - номер колонки, Y - номер строки на экране). Таким образом можно ввести массив размером не более 20 на 20.
Вывод выглядит точно также:
for i := 1 to 5 do
for j := 1 to 5 do
begin
gotoxy(X+j*5, Y+i);
write(a[i, j]);
end;

 

IV. Примеры решения задач.
 

Разберем пример.
Найти сумму элементов, лежащих ниже главной диагонали, в целочисленном массиве A [n, n].
Формулу изменения элементов мы уже разобрали, поэтому сразу алгоритм:

1. Ввести n
2. Проверить n на допустимость
3. Ввести массив n на n
4. Обнулить сумму
5. Просуммировать нужные элементы
6. Вывести сумму.

Программа на Паскале, реализующая этот алгоритм (cумму назовем s):

program prim1;
uses crt;
type arr2dim = array [1..10,1..10] of integer;
var a: arr2dim;
i, j, s, n: integer;
begin
clrscr;
textcolor(lightcyan);
writeln('Суммирование элементов массива');
textcolor(green);
repeat
write('Введите размер массива n=');
readln(n);
if (n < 0) or (n > 10) then writeln('неверно (0 < n < 10)');
until (n > 0) and (n < 10);
writeln('Введите элементы массива:');
for i := 1 to n do
for j := 1 to n do
begin
gotoxy(5+j*5,6+i);
readln(a[i, j]);
end;
s := 0;
for i := 1 to n do
for j := 1 to i-1 do
s := s + a[i, j];
writeln('Сумма элементов ниже главной диагонали равна ', s);
readkey;
end.

Здесь новый способ проверки значения n на допустимость. Ввод n будет повторяться до тех пор, пока не введется правильное значение.
Во внутреннем цикле подсчета суммы переменная j изменяется до i-1, а не до i, т.к. элементы самой главной диагонали в сумму не включаются.

Разберем второй пример - с преобразованием введенного массива.

Ввести целочисленный массив A [n, n] и преобразовать по правилу: вычесть из каждой строки предыдущую. Из первой строки вычесть последнюю. Получившийся массив вывести.

Исходный массив Результат
1 8 5 1 -4 1 -4 -2
8 5 2 0 7 -3 -3 -1
4 4 2 6 -4 -1 0 6
5 7 9 3 1 3 7 -3


Как написать цикл преобразования? И куда записывать результат - в исходный массив или другой?
Чтобы получить i-тую строку массива-результата, необходимо из i-той строки исходного массива вычесть (i-1)-ую. Следовательно, 2-я строка массива-результата получится вычитанием 1-ой из 2-ой, 3-я - вычитанием 2-ой из 3-ей и т.д. Отсюда понятно, что каждая строка исходного массива используется ДВА раза, и, значит, результат записывать в исходный массив нельзя (записав туда, к примеру, 2-ю строку, мы не сможем получить 3-ю строку результата, так как для ее вычисления необходима 2-я строка, а она уже затерта). Поэтому результат будем записывать в другой массив, не исходный.

Что же касается цикла обработки, то его можно сформулировать так: для всех строк от 2-й до последней вычесть из i-той (i -1)-ую. Из первой строки нужно вычесть последнюю - запишем это как особый случай (если вычисляем 1-ую строку результата, вычитаем из 1-ой исходной не (1-1)-ую, а n-ную, сделаем такое исключение с помощью дополнительной проверки).
Вычитание строк заключается в том, что вычитаются все элементы попарно.
Пусть исходный массив называется А, а массив-результат - В.

Тогда алгоритм решения можно описать так:

1. Ввести n
2. Проверить n на допустимость
3. Ввести массив A
4. Для всех строк массива A: {пусть номер текущей строки i}
4.1. если номер текущей строки = 1 то номеру предыдущей строки присвоить значение n иначе номеру предыдущей строки присвоить значение номер текущей строки - 1
4.2. Для всех элементов текущей строки вычесть из элемента текущей строки массива А соответствующий элемент предыдущей строки массива А и записать в соответствующий элемент массива В. { если номер текущей равен 1, то "предыдущей" будет последняя строка массива А}
5. Вывести массив В

Этот алгоритм реализует такая программа на языке Паскаль (k - это номер "предыдущей строки"):

program prim2;
uses crt;
type arr2dim = array [1..10,1..10] of integer;
var a, b: arr2dim;
i, j, k, n: integer;
begin
clrscr;
textcolor(lightcyan);
writeln('Вычитание строк массива');
textcolor(green);
repeat {шаги 1 и 2}
write('Введите размер массива n=');
readln(n);
if (n < 0) or (n > 10) then writeln('неверно (0 < n < 10)');
until (n > 0) and (n < 10);
writeln('Введите элементы массива:');
for i := 1 to n do {шаг 3}
for j := 1 to n do
begin
gotoxy(5+j*5,6+i);
readln(a[i, j]);
end;
for i := 1 to n do
begin
if i=1 then k := n else k := i-1; {шаг 4.1}
for j := 1 to n do {шаг 4.2}
b[i, j] : = a[i, j] - a[k, j];
еnd;
writeln('Результат:');
for i := 1 to n do {шаг 5}
for j := 1 to n do
begin
gotoxy(5+j*5,15+i);
write(b[i, j]);
end;
readkey;
end.
 

Сайт создан в системе uCoz