учебник по паскалю. Программа 5 Алгоритм 5 Свойства алгоритма 6 Формы записи алгоритма 6
Скачать 2.21 Mb.
|
18.3. Массивы в качестве параметров подпрограммыЗачастую подпрограмма-процедура или функция должна обработать некоторый массив данных. Однако структурный тип массива нельзя непосредственно указать в списке формальных параметров. В этом случае тип массива объявляется заранее в разделе описаний с помощью подраздела type: type ИмяТипа = ОписаниеМассива; Здесь ИмяТипа -- даваемое программистом наименование нового типа данных, а ОписаниеМассива -- известный нам оператор описания вектора или матрицы. Например, если подпрограмма должна обрабатывать вещественные массивы, не превышающие по размерности десяти элементов, в разделе описаний программы имеет смысл сделать следующее объявление: type vector = array [1..10] of real; Поскольку новый тип данных vector предназначен для использования подпрограммами, указанное выше объявление располагается до всех подпрограмм. В дальнейшем тип данных vector можно использовать как в разделе описания переменных var a,b:vector;, так и в списке формальных параметров функции или процедуры: function work (a:vector):real; Если по условию задачи в подпрограмме требуется при разных обращениях обрабатывать массивы различной размерности, то в разделе type объявляется тип массива с наибольшей из размерностей, встречающихся в задаче. Это чревато тем, что при обработке массивов меньшей размерности часть памяти останется неиспользованной. Кроме того, при обращении к подпрограмме в этом случае приходится отдельным параметром передавать фактическую размерность массива. Допустим, с помощью подпрограммы требуется найти максимальные элементы матриц A3x4, B4x3, C4x5. С учетом максимальной из имеющихся размерностей, делаем объявление типа matrix в разделе описаний: type matrix = array [1..4,1..5] of real; Далее описываем конкретные матрицы как объекты нового типа данных matrix: var a,b,c:matrix; В качестве подпрограммы поиска значения максимального элемента матрицы напишем функцию max1 (функцию, а не процедуру, поскольку максимум -- скалярное значение). В эту функцию нам придется передать 2 дополнительных параметра-значения, определяющих количество строк n и количество столбцов m в конкретной матрице, переданной фактическим параметром: function max1 (n,m:integer; var a:matrix):real; var max:real; i,j:integer; begin max:=a[1,1]; for i:=1 to n do for j:=1 to m do if a[i,j]>max then max:=a[i,j]; max1:=max; end; Использование дополнительной локальной переменной max связано с теми же причинами, что в первом примере на функции. Обратите внимание, что, хотя функция max1 и не изменяет элементы своих матриц-параметров, в списке ее формальных параметров матрица указана как параметр-переменная. Для матриц и векторов это рекомендуется делать всегда, поскольку при указании параметра-переменной в матрицу передается только адрес того места памяти, где хранятся ее данные, а не копия всех элементов. В конечном счете, передача матриц и векторов формальным параметрам-переменным позволяет уменьшить размер генерируемого машинного кода. Вызвать нашу функцию для матриц A, B и C мы могли бы так: var ma,mb,mc:real; ... ma:=max1(3,4,a); mb:=max1(4,3,b); mc:=max1(4,5,c); Более удобную работу с массивами-параметрами предлагает механизм открытых массивов, рассмотренный в п. 18.4. Однако его непосредственно используют лишь для одномерных массивов. Пока же рассмотрим примеры решения типовых задач. 1. Заданы вектора A и B, содержащие по 5 элементов. Используя подпрограмму, найти их скалярное произведение по формуле Поиск скалярного произведения реализуем в виде подпрограммы-функции scal. type vector=array [1..5] of real; function scal (n:integer; var a,b:vector):real; var i:integer; s:real; begin s:=0; for i:=1 to n do s:=s+a[i]*b[i]; scal:=s; end; var i:integer; a,b:vector; s:real; begin writeln ('Вектор 1 из 5 элементов:'); for i:=1 to 5 do read (a[i]); writeln ('Вектор 2 из 5 элементов:'); for i:=1 to 5 do read (b[i]); s:=scal(5,a,b); writeln ('s=',s:10:3); end. 2. Сформировать по введенному с клавиатуры вектору A размерности n вектор res, компонентами которого являются отклонения элементов A от их арифметического среднего (подобная задача уже решалась выше, расширим ее на случай вектора). Задача предполагает написание, по меньшей мере, двух подпрограмм: функция Middle будет вычислять арифметическое среднее элементов вектора, а процедура Otkl – формировать по вектору A и ранее найденному среднему mid искомый вектор отклонений b. Компоненты вектора b при этом будут вычисляться по формуле . Поскольку о размерности векторов в задаче ничего не сказано, укажем в разделе type максимальную размерность, равную 100 элементам. type vector= array [1..100] of real; function Middle (n:integer; var a:vector):real; var j:integer; res:real; begin res:=0.0; for j:=1 to n do res:=res+a[j]; Middle:=res/n; end; procedure Otkl (n:integer; mid:real; var a,b:vector); var j:integer; begin for j:=1 to n do b[j]:=abs(a[j]-mid); end; var a,res: vector; i,n:integer; s:real; begin write ('Размерность? '); readln (n); for i:=1 to n do begin write ('A[',i,']='); readln (a[i]); end; s:=Middle (n,a); Otkl (n,s,a,res); for i:=1 to n do writeln ('res[',i,']=',res[i]:8:2); end. 3. Используя подпрограмму, написать и проверить программу перемножения двух матриц. Как известно, матрица A размерностью nm может быть умножена на матрицу B размерностью mp по следующей формуле: где ci,j -- элемент получающейся в результате перемножения матрицы С размерностью nm. Из формулы видно, что для умножения двух матриц нам понадобится тройной цикл: внешний цикл по i перебирает строки матрицы A, вложенный в него цикл по j выбирает в матрице B очередной столбец, а самый внутренний цикл по l умножает строку матрицы A на столбец матрицы B, получая элемент ci,j. Напишем соответствующую процедуру mmul и тестовую программу для нее: type matrix=array[1..10,1..10] of real; var a,b,c: matrix; i,j,n,m,p: integer; procedure mmul (n,m,k:integer; var a,b,c:matrix); var i,j,l:integer; s:real; begin for i:=1 to n do for j:=1 to k do begin s:=0; for l:=1 to m do s:=s+a[i,l]*b[l,j]; c[i,j]:=s; end; end; begin repeat writeln; write ('Введите количество строк ', '1 матрицы: '); readln (n); write ('Введите количество столбцов ', '1 матрицы: '); readln (m); write ('Введите количество столбцов ', '2 матрицы: '); readln (p); until (n>1) and (n<11) and (m>1) and (m<11) and (p>1) and (p<11); for i:=1 to n do begin writeln ('Введите строку ',i, ' матрицы A из',m,'элементов:'); for j:=1 to m do read (a[i,j]); end; for i:=1 to m do begin writeln ('Введите строку ',i, ' матрицы B из',p,'элементов:'); for j:=1 to p do read (b[i,j]); end; mmul (n,m,p,a,b,c); for i:=1 to n do begin writeln; for j:=1 to p do write (c[i,j]:10:3); end; end. 4. Процедурно ориентированные программы для распространенных задач решения системы линейных уравнений методом Гаусса, сортировки одномерного массива, поиска всех миноров второго порядка в квадратной матрице Вы можете найти и самостоятельно разобрать в Приложении 4. 5. В качестве еще одного развернутого примера на использование массивов в подпрограммах, разберем следующую задачу. Имеется N городов, между которыми налажены пассажирские перевозки. Между какими городами самый активный пассажиропоток? Количество городов обозначим константой cities. После математической формализации задачи, нетрудно заметить, что перевозки из города i в город j могут быть занесены в элемент матрицы ai,j, таким образом, требуется определить величину max(ai,j+aj,i), учитывая перевозки "туда" и "обратно". Для поиска максимального пассажиропотока достаточно двойного цикла с переменной границей по счетчику вложенного цикла. Как и в других программах, выделим в отдельные подпрограммы также типовые задачи ввода и вывода матрицы, а также ввода вещественного значения с контролем допустимых числовых границ ввода. const cities=10; type matrix=array [1..cities,1..cities] of integer; function max1 (n:integer; var a:matrix; var imax,jmax:integer):integer; var i,j,m,p:integer; begin m:=a[1,2]; imax:=1; jmax:=2; for i:=1 to n do for j:=1 to n do if (i<>j) then begin p:=a[i,j]+a[j,i]; if p>m then begin m:=p; imax:=i; jmax:=j; end; end; max1:=p; end; function readNumber (s:string; min,max:integer):integer; var a:integer; begin repeat write (s); {$I-}readln(a);{$I+} if IoResult<>0 then writeln ('Ошибка, введено не число!') else if (a writeln ('Ошибка, введенное число ', 'принадлежит интервалу [',min, ',', max, ']') else break; until false; readNumber:=a; end; procedure readMatrix1 (var n:integer; var a:matrix); var i,j:integer; s,s1:string; begin n:=readNumber ('Введите число строк ', 'и столбцов матрицы: ',2,cities); for i:=1 to n do for j:=i+1 to n do begin s:='A['; str(i,s1); s:=s+s1+','; str(j,s1); s:=s+s1+']='; a[i,j]:=readNumber (s,0,maxInt); end; end; procedure writeMatrix1 (s:string; n:integer; var a:matrix); var i,j:integer; begin writeln (s); for i:=1 to n do begin for j:=1 to n do write (a[i,j]:7); writeln; end; end; var a:matrix; n,gorod1,gorod2:integer; begin readMatrix1 (n,a); max1 (n,a,gorod1,gorod2); writeMatrix1 ('A=',n,a); writeln ('Самый большой пассажиропоток ', 'между городами ',gorod1,' и ',gorod2); readln; end. |