Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Интегрирование Глава 10.doc
Скачиваний:
4
Добавлен:
12.11.2018
Размер:
1.28 Mб
Скачать

Выбор метода решения

Анализ математической модели показывает, что решение задачи требует многократного вычисления суммы элементов каждой строки двумерных массивов A и B. В первом случае m элементов сумм массива A, во втором – t элементов сумм массива B.

Результаты вычислений для положительных сумм каждой исходной матрицы требуется представить одномерными массивами SSA(mp) и SSB(tp), где mp и tp – размеры созданных массивов. Такое вычисление удобно выполнить смешанным процессом, оформленным дополнительным алгоритмом. Входным параметром этого алгоритма будет исходный двумерный массив, а выходным – результирующий одномерный.

Для рассматриваемой задачи в качестве входных формальных параметров дополнительного алгоритма выберем, например, имя массива Z и его размеры k, p. Тогда в качестве выходных параметров можно использовать одномерный массив SSZ размером d (количеством положительных сумм). Следовательно, в качестве формальных параметров выбраны Z, k, p, SSZ, d.

Для работы с подпроцессом необходимы обращения к нему из основного алгоритма. Естественно, что в обращениях должны использоваться входные и выходные фактические параметры.

Поэтому, задавшись именем подпрограммы sum_str, сформируем два обращения к ней: для расчёта положительных сумм элементов строк массива A – sum_str(A, m, n ,SSA, mp) и для тех же вычислений с массивом B – sum_str(B, t, s, SSB, tp). Два начальных параметра в каждом обращении являются входными, определяя имя и размеры передаваемого в подпрограмму двумерного массива. Два последних параметра являются выходными, предназначенными для получения одномерного массива значений положительных сумм строк из подпрограммы.

Следовательно, рациональный метод решения задачи – вычислительный процесс с одним подпроцессом при использовании основного алгоритма с обращениями sum_str(A, m, n, SSA, mp) и sum_str(B, t, s, SSB, tp) и дополнительного алгоритма с формальными параметрами Z, k, p, SSZ, d.

Составление алгоритма решения

Выбранный метод решения предписывает, что основной алгоритм реализует ввод и вывод исходных двумерных матриц.

Дополнительный – производит вычисление текущего значения суммы элементов каждой строки, проверку его знака с оформлением положительных сумм в формальный одномерный массив. При формировании этого массива используется параметр цикла (индекс d), изменяющий своё значение от начального (d = 0) до конечного по закону изменения d = d + 1 для каждой положительной суммы. Полученное конечное значение индекса определяет искомые значения размеров создаваемых массивов SSA(mp) и SSB(tp).

Обращение к дополнительному алгоритму производится двукратно, что позволяет последовательно передать в него каждый из исходных массивов. Графическая реализация алгоритмов представлена схемами рис. 10.16.

Программирование задачи

Особенность составленных алгоритмов – необходимость передачи в дополнительный алгоритм многомерных массивов и возвращения в основной результатов в виде одномерных массивов.

Рис. 10.16. Схемы основного и дополнительного алгоритмов задачи о суммах строк двумерных матриц

Программно передача многомерного массива в дополнительную функцию в качестве входного осуществляется аналогично одномерному – указанием адреса первого элемента и размеров по каждому измерению (целых переменных).

  • Внимание! Механизмы передачи входных и выходных массивов аналогичны.

Каждый выходной формальный массив, создаваемый в вызываемой функции для возвращения результатов, должен быть описан в вызывающей как один или несколько аналогичных массивов. Количество описываемых массивов определяет пользователь в зависимости от условий задачи с несколькими обращениями.

Описатели массивов определяют максимально возможные размеры каждого измерения и позволяют пользователю заполнять зарезервированное пространство оперативной памяти полностью, либо частично, обеспечивая универсальность размеров в сторону уменьшения. Размеры, указанные в описателе, определяют количество зарезервированных в памяти ячеек. При этом ячейки создаваемого двумерного массива располагаются последовательно и линейно (построчно).

Если в расчетах зарезервированное пространство используется частично (с меньшим числом строк и/или столбцов), то участки с хранимыми значениями будут чередоваться с неиспользуемыми, количество которых должно быть учтено при указании длины каждой строки в индексном выражении.

Суммарное количество элементов каждой строки задано в описателе массива. Поэтому адрес любой ячейки определяется индексным выражением, использующим в качестве одного из операндов указанный в описателе размер.

Следовательно, в функцию необходимо наряду с используемым фактическим размером передавать и максимальный, указанный в описателе.

Если возвращаемые результаты не требуется хранить для последующего использования, достаточно описать один массив и использовать его многократно (последовательно при каждом обращении к функции). Если все возвращаемые массивы результатов требуется хранить, в вызывающей функции каждый из них должен быть описан как самостоятельный с уникальным именем и размером, определяемым логикой задачи. В этом случае в каждом обращении к дополнительной функции используется своё имя и размер. Если фактический размер выходного массива заранее известен, передача его осуществляется по значению, если рассчитывается в дополнительной функции – передаётся (возвращается) по адресу.

  • Внимание! Если размер выходного массива совпадает с одним из параметров входного, то указывать его не требуется.

В рассматриваемом примере используются два входных двумерных (a, b) и два выходных одномерных (ssa, ssb) массива. Исходя из условий задачи, предполагаем хранение выходных массивов. Следовательно, в основной функции должны быть описаны четыре массива (a, b, ssa, ssb). Элементы входных будут определены вводом значений в этой же (основной) функции, выходных – после соответствующих обращений к подпрограмме.

Работа в дополнительной функции с элементами многомерного массива производится операцией разадресации определяющего их индексного выражения.

Методика хранения многомерных массивов (разд. 9.1.1.2) позволяет рассчитывать адрес каждого элемента через начальный адрес массива, добавляя к нему сумму произведений увеличенных размеров на длину ячейки для хранения каждого элемента.

  • Внимание! Особенности обращения к элементам многомерных массивов – учет максимальных значений размеров по каждому измерению. Поэтому в вызове функции и её заголовке для каждого массива указывается его адрес, фактические размеры по каждому измерению и увеличенные размеры (исключая первое измерение).

Так, при передаче в дополнительную функцию двумерного массива A(mxn) с максимально требуемым размером 10x15, фрагмент обращения имеет вид

float a[10][15];

. . .

func(a[0], m, n, 15);

. . .

а заголовок дополнительной функции запишется, например, следующим образом

void func(float *z, int k, int p, int t)

при этом обращение к текущему элементу zij имеет вид

*(z + i * t + j)

С учетом изложенного, выполним программирование задачи 10.4. Идентификация переменных представлена в табл. 10.4.

Таблица 10.4

Обозначение в алгоритме

1

m

n

t

s

i

j

aij

bij

Обозначение в программе

2

m

n

t

s

i

j

a[i][j]

b[i][j]

Окончание табл. 10.4

1

ssai

ssbi

mp

tp

k

p

ss

d

sszd

zij

2

ssa[i]

ssb[i]

mp

tp

k

p

ss

d

ssz[d]

z[i][j]

Анализ алгоритма показывает, что основной выходной параметр оформлен в виде одномерного массива. Поэтому с учетом таблицы идентификации, рассмотренных выше правил и расчета в дополнительной функции размера возвращаемого массива, обращения примут вид:

sum_str( a, m, n, 15, ssa, &mp); и sum_str( b, t, s, 7, ssb, &tp);

где m, n, t, s – фактические используемые размеры, 15 и 7 – фактические максимальные размеры по второму измерению массивов A и B, а &mp и &tp – адреса размеров возвращаемых массивов.

Заголовок дополнительной функции преобразуется к виду:

void sum_str(float *z, int k, int p, int pmax, float *ssz, int *d)

где k и p – формальные используемые размеры, а pmax – формальный максимальный размер по второму измерению массива Z, *d – указатель размера создаваемого массива.

Универсальные размеры массивов зададим подстановочными директивами define, что позволит модифицировать увеличенные размеры всех массивов в заголовочной части программы.

Классический вариант программирования задачи

#include<stdio.h>/*файл с прототипами функций ввода-вывода*/

#include<conio.h>/*файл с прототипом функции getch(), clrscr()*/

#include <windows.h> /*файл с прототипом функции CharToOem*/

#define M 10 /* присваивание*/

#define N 15 /*максимальных*/

#define T 9 /*размеров*/

#define S 7 /*массивов А и В*/

void sum_str(float* z, int k, int p, int pmax, float *ssz, int *d);

main( ) /* заголовок головной функции */

{

float ap, bp, a[M][N], b[T][S], ssa[M], ssb[T]; /*описатели */

int i, j, n, m, t, s, mp, tp; /* массивов и переменных*/

char buf[30];

clrscr( );

CharToOem(" Введите значения n, m, t, s: ",buf);

printf("\n %s \n",buf);

scanf("%d%d%d%d", &m, &n, &t, &s);

printf("\n m=%d n=%d \n t=%d s=%d \n", m, n, t, s);

CharToOem(" Введите построчно массив A ",buf);

printf("\n %s (%d*%d):\n", buf, m, n);

for( i = 0 ; i < m ; i++ )/*заголовок внешнего цикла ввода a[i][j]*/

for( j = 0 ; j < n ; j++ )/*заголовок внутрен. цикла ввода a[i][j]*/

scanf("%f", a[0] + i * N + j );

CharToOem("Массив A ",buf);

printf("\n %s \n", buf);

for( i = 0 ; i < m ; i++ )/* заголовок внешн. цикла вывода a[i][j]*/

{

for( j = 0 ; j < n ; j++ )/*заголовок внутр. цикла вывода a[i][j]*/

printf(" %6.2f", a[i][j]);

printf("\n");

}

CharToOem(" Введите построчно массив B ",buf);

printf("\n %s (%d*%d):\n", buf, t, s);

for( i = 0 ; i < t ; i++ ) /* заголовок внешнего цикла ввода b[i][j]*/

for( j = 0 ; j < s ; j++ ) /* заголовок внутр. цикла ввода b[i][j]*/

scanf("%f", b[0] + i * S + j );

CharToOem("Массив B ",buf);

printf("\n %s \n", buf);

for( i = 0 ; i < t ; i++ ) /* заголовок внешн. цикла вывода b[i][j]*/

{

for( j = 0 ; j < s ; j++ ) /* заголовок внутр. цикла вывода b[i][j]*/

printf(" %6.2f", b[i][j]);

printf("\n");

}

sum_str( a[0], m, n, N, ssa, &mp);

CharToOem("Массив SSA ",buf);

printf("\n %s \n", buf);

for( i = 0 ; i < mp ; i++ ) /* заголовок цикла вывода ssa[ i ] */

printf(" %.2f",ssa[i]);

printf("\n"); /* перевод курсора в начало следующей строки */

sum_str( b[0], t, s, S, ssb, &tp);

CharToOem("Массив SSB ",buf);

printf("\n %s \n", buf);

for( i = 0 ; i < tp ; i++ ) /* заголовок цикла вывода ssb[ i ] */

printf(" %.2f",ssb[i]);

printf("\n"); /* перевод курсора в начало следующей строки */

getch( );

}

void sum_str(float *z, int k, int p, int pmax, float *ssz, int *d)

{

int i, j; /* описание локальных */

float ss; /* переменных */

*d = 0;

for( i = 0 ; i < k ; i++ ) /*заголовок внешн. цикла расчета ss*/

{

ss = 0;

for( j = 0 ; j < p ; j++ ) /* заголовок внутр. цикла расчета ss */

{

ss = ss + *(z + i * pmax + j);

}

if( ss >= 0 )

{

ssz[*d] = ss;

*d=*d + 1;

}

}

}

3 4 2 3 – реальные размеры массивов А и В;

8.53 9.3 5.7 -3.5 – значения

46 -32.1 28.5 -52.6 элементов

4.7 56 65 -7.2 массива А;

1.6 7.3 15 – значения элементов

4.2 -10.18 12 массива В.

Под закрывающей скобкой приведены исходные данные для решения задачи.

Результаты решения представлены в приложении 10.7.

Программирование задачи с графическим интерфейсом

Программирование задачи при использовании графического интерфейса предварим его разработкой.

ListBoxA

ListBoxB

Для ввода значений n, m, t, s планируем однострочные поля редактирования (EditN, EditM, EditT, EditS). Для ввода элементов массивов A и B используем многострочные поля редактирования (EditA, EditB). Вывод форматированных массивов А и В и расчетных значений ssa и ssb реализуем в поля-списки (ListBoxA, ListBoxB, ListBoxSSA, ListBoxSSB).

Управление процессом решения реализуем двумя командными кнопками, расположенными в нижней части окна. Назначение каждой определяется ее названием.

С учетом планируемого интерфейса выполним программирование задачи.

#include <stdio.h>/*файл с прототипами функций ввода-вывода*/

#define M 10 /* присваивание*/

#define N 15 /*максимальных*/

#define T 9 /*размеров*/

#define S 7 /*массивов А и В*/

void sum_str(float* z, int k, int p, int pmax, float *ssz, int *d);

void TSumprDlgClient::BNClickedOk()

{

// INSERT>> Your code here.

float ap, bp, a[M][N], b[T][S], ssa[M], ssb[T]; /* описатели */

int i, j, n, m, t, s, mp, tp; /*массивов и переменных*/

char buf[15], buf1[50]="";

ListBoxA->ClearList();

ListBoxB->ClearList();

ListBoxSSA->ClearList();

ListBoxSSB->ClearList();

EditN->GetText(buf,10); /*ввод */

n=atoi(buf); /*значения n*/

EditM->GetText(buf,10); /*ввод */

m=atoi(buf); /*значения m*/

EditT->GetText(buf,10); /*ввод */

t=atoi(buf); /*значения t*/

EditS->GetText(buf,10); /*ввод */

s=atoi(buf); /*значения s*/

for( i = 0 ; i < m ; i++ )/*заголовок внешн. цикла ввода a[i][j]*/

for( j = 0 ; j < n ; j++ )/*заголовок внутрен. цикла ввода a[i][j]*/

{

EditA->GetLine(buf, sizeof(buf),i*n+j);

a[i][j] = atof(buf);

}

for( i = 0 ; i < m ; i++ )/* заголовок внешн. цикла вывода a[i][j]*/

{

strcpy(buf1, "");

for( j = 0 ; j < n ; j++ )/*заголовок внутр. цикла вывода a[i][j]*/

{

sprintf(buf,"%.2f ", a[i][j]);

strcat(buf1, buf); /*слияние строк buf и buf1*/

}

ListBoxA->AddString(buf1);

}

for( i = 0 ; i < t ; i++ )/*заголовок внешн. цикла ввода b[i][j]*/

for( j = 0 ; j < s ; j++ )/*заголовок внутр. цикла ввода b[i][j]*/

{

EditB->GetLine(buf, sizeof(buf),i*s+j);

b[i][j] =atof(buf);

}

for( i = 0 ; i < t ; i++ )/* заголовок внешн. цикла вывода b[i][j]*/

{

strcpy(buf1, ""); /*очистка содержимого строки buf1*/

for( j = 0 ; j < s ; j++ ) /* заголовок внутр. цикла вывода b[i][j]*/

{

sprintf(buf,"%.2f ", b[i][j]);

strcat(buf1, buf); /*слияние строк buf и buf1*/

}

ListBoxB->AddString(buf1);

}

sum_str( a[0], m, n, N, ssa, &mp);

for( i = 0 ; i < mp ; i++ ) /* заголовок цикла вывода ssa[ i ] */

{

sprintf(buf,"%.2f ", ssa[i] );

ListBoxSSA->AddString(buf);

}

sum_str( b[0], t, s, S, ssb, &tp);

for( i = 0 ; i < tp ; i++ ) /* заголовок цикла вывода ssb[ i ] */

{

sprintf(buf,"%.2f ", ssb[i] );

ListBoxSSB->AddString(buf);

}

}

void sum_str(float *z, int k, int p, int pmax, float *ssz, int *d)

{

int i, j; /* описание локальных */

float ss; /* переменных */

*d = 0;

for( i = 0 ; i < k ; i++ )/* заголовок внешнего цикла расчета ss*/

{

ss = 0;

for( j = 0 ; j < p ; j++ ) /* заголовок внутр. цикла расчета ss */

{

ss = ss + *(z + i * pmax + j);

}

if( ss >= 0 )

{

ssz[*d] = ss;

*d=*d + 1;

}

}

}

3 4 2 3 – реальные размеры массивов А и В;

8.53 9.3 5.7 -3.5 – значения

46 -32.1 28.5 -52.6 элементов

4.7 56 65 -7.2 массива А;

1.6 7.3 15 – значения элементов

4.2 -10.18 12 массива В.

Под закрывающей скобкой приведены исходные данные для решения задачи.

Результаты решения представлены в приложении 10.8.