Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Ситкин. Информатика. Программирование в DELPHI

.pdf
Скачиваний:
142
Добавлен:
18.07.2019
Размер:
1.49 Mб
Скачать

Лабораторная работа № 8

МАССИВЫ

Цель работы приобретение умений разработки и программной реализации алгоритмов обработки массивов.

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

массив совокупность пронумерованных однотипных переменных.

Объявление массива

При объявлении массива нужно указать его характеристики:

имя массива общее имя переменных, составляющих массив;

диапазон изменения номера переменной (индекса), тем самым определяется число элементов массива, т.к. значения индекса заполняют без пропусков через единицу весь интервал;

тип элементов массива.

В общем виде объявление (описание) массива выглядит так var имя_массива : array[нижн_индекс..верхн_индекс] of тип ;

здесь array и of служебные слова; имя массива выбирает программист; в квадратных скобках указывают границы изменения индекса, обычно это целые числа; тип тип переменных, составляющих массив. Объявление массива служит командой компилятору для выделения указанного числа пронумерованных ячеек памяти при компиляции для последующего хранения в них значений переменных

91

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

Реальный массив может быть меньше (но не больше) объявленного.

Рассмотрим примеры объявлений массивов. 1. Через объявление переменной

var x:array[1..10] of byte; //массив из десяти переменных целого типа y:array[0..9] of real; //массив из десяти переменных вещественного

//типа, пронумерованных от 0 до 9 z:array[-5..5] of char; //массив из одиннадцати переменных

//символьного типа, пронумерованных от -5 до 5 d:array[byte] of string; //массив из 256 переменных строкового типа,

//пронумерованных от 0 до 255

2. Через объявление пользовательского типа данных массив, а

затем объявление переменной этого типа type mass = array[1..10] of integer;

var x:mass;

3. С использованием имён констант const m=1; n=25;

type mas1 = array[m..n] of single; mas2 = array[-n..n] of double;

var x:mas1; //массив из 25-ти вещественных переменных (элементов) y, z:mas2; //два массива из 51-го вещественного элемента каждый

В программном коде для обращения к элементу массива запи-

сывают имя массива с указанием номера элемента в квадратных скоб-

ках. В качестве индекса может выступать константа, переменная или выражение. Все они должны быть целого (порядкового) типа, напри-

мер: x[1]; x[i]; x[i+1] и т.п.

92

Обработка массивов

Для обработки массивов используют операторы циклов, в теле

которых индекс пробегает ряд значений. Рассмотрим некоторые ти-

повые примеры (фрагменты). Пусть имеются следующие описания const n=10;

type vector = array[1..n] of real; var x:vector;

S, max:real; i:byte;

1. Сформировать массив из n случайных вещественных чисел в диа-

пазоне от нуля до единицы

Фрагмент блок-схемы

Реализация с while

Реализация с for

 

 

 

 

Randomize;

Randomize;

 

i = 1

 

 

 

 

 

 

i:= 1;

for i:=1 to n do

 

 

 

 

 

i n

нет

while i = n do

x[i]:=Random;

 

 

 

 

 

 

да

 

 

begin

 

 

 

 

 

x[i]:=Random;

 

 

xi=случ. вещ.

 

 

 

 

число 0..1

 

 

i:=i+1;

 

 

 

 

 

 

 

 

 

 

end;

 

 

 

 

 

 

 

i = i + 1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Чтобы воспользоваться генератором случайных чисел, его нуж-

но сначала инициализировать оператором Randomize, после этого можно вызывать стандартную функцию Random. В работе с массива-

ми удобен оператор цикла for (частный случай оператора while, спе-

циально созданный для работы с массивами).

93

2. Найти сумму элементов массива (элементы уже введены в память)

Фрагмент блок-схемы

Реализация с while

Реализация с for

 

 

 

 

S:=0;

S:=0;

 

S = 0, i = 1

 

 

 

 

 

 

i:= 1;

for i:=1 to n do

 

 

 

 

 

i n

нет

while i = n do

S:= S + x[i];

 

 

 

 

 

 

да

 

 

begin

 

 

 

 

 

S:= S + x[i];

 

 

S = S + xi

 

 

 

 

 

 

 

 

 

 

 

 

i:=i+1;

 

 

 

 

 

end;

 

 

 

 

 

 

 

i = i + 1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

3. Найти номер первого отрицательного элемента (полагаем, что эле-

менты массива введены и хотя бы один из них отрицательный)

Реализация с while

Реализация с repeat .. until

i = 1

i:= 1;

i = 0

 

 

i:= 0;

 

 

 

while x[i] =0

 

repeat

xi 0

нет

 

 

do i:=i+1;

i = i + 1

i:=i+1;

да

Label.Caption:=

 

until x[i] 0;

 

 

i = i + 1

IntToStr(i);

нет

Label.Caption:=

xi 0

 

 

 

 

да

IntToStr(i);

вывод i

 

вывод i

 

 

 

 

94

4. Найти наибольший элемент массива Алгоритм, фрагмент блок-схемы которого представлен на рис. 8.1,

 

 

 

 

следующий. После того, как элементы мас-

max = x1

 

 

 

 

сива уже введены в память (в схеме нет вво-

i = 2

 

 

 

 

 

 

 

нет

да), делают предположение, что первый

 

 

i n

элемент имеет максимальное значение, ко-

 

 

да

 

 

торое записывается в переменную max. За-

xi max

нет

тем, начиная со второго элемента, в теле

 

 

 

да

 

 

цикла «прогоняют» все остальные элемен-

 

 

 

 

 

 

 

ты, сравнивая с max. Если на i-ой итерации

max = xi

 

 

 

 

обнаруживается элемент, значение которого

 

 

 

 

 

 

 

 

больше max, то в переменную max записы-

 

 

 

 

 

 

 

 

i = i + 1

 

 

 

 

вается значение i-го элемента, «затирая»

 

 

 

 

предыдущее значение получают новое

 

 

 

 

 

 

 

 

промежуточное значение max. Если в по-

вывод

 

 

следующей итерации обнаружится элемент

max

 

 

 

 

 

 

 

 

 

со значением больше нового max, то вновь в

Рис. 8.1

 

 

переменную max запишется новое значение

 

 

 

 

и т.д., пока не закончатся элементы. В результате к концу процесса

«вытягивается» максимальное значение массива.

max:= x[1]; i:= 2;

max:= x[1];

while i = n do begin

for i:=2 to n do

if x[i] max then

if x[i] max then

max:= x[i];

max:= x[i];

i:=i+1;

Label.Caption:= FloatToStr(max);

end;

 

Label.Caption:= FloatToStr(max);

 

 

 

95

Пример 8.1

 

 

 

 

 

Разработаем алгоритм и проект для умножения отрицательных

элементов массива на заданный коэффициент и подсчёта их числа.

начало

 

Блок-схема алгоритма решения пред-

 

 

 

 

 

 

 

ставлена на рис. 8.2. После ввода коэффи-

ввод

 

циента

домножения

k

устанавливаются

коэфф. k

 

счётчик h=0

 

начальные значения

счётчика отрицатель-

 

 

 

 

 

n=число эл-ов

 

ных элементов h и индекса элемента i. В

индекс i = 1

 

цикле после ввода i-го элемента в память

 

 

i n

нет

каждый проверяется на знак. Если текущий

 

да

 

элемент отрицательный, то он умножается

ввод xi

 

на k, это значение «затрёт» старое, а счёт-

 

 

 

 

 

 

 

чик h увеличит своё значение на единицу. В

xi 0

нет

противном случае эти две операции пропу-

 

 

 

 

 

да

 

стятся. Независимо от этого условия в теле

 

 

 

 

 

xi = kxi

 

цикла выводится i-ый элемент и осуществ-

h = h + 1

 

ляется переход к следующему по номеру

 

 

элементу. Процесс продолжается, пока ин-

вывод xi

 

декс не превысит число элементов в масси-

 

 

ве. Значение счётчика отрицательных чисел

i = i + 1

 

выводится уже после окончания цикличе-

 

 

ского процесса, т.к. это значение одно.

 

 

Реализуем алгоритм

в проекте. Для

вывод h

 

ввода массива с формы удобно использо-

 

 

 

 

вать компонент Memo, расположив в нём по

конец

 

одному элементу в строке. Свойства ком-

 

 

Рис. 8.2

 

понента описаны в работе 1.

 

 

96

x[i]:=StrToFloat(Memo1.Lines[i-1]);

procedure TForm1.Button1Click(Sender: TObject);

const m=100;

var x: array[1..m] of real;

i, n, h:byte;

k:real;

begin

k:=StrToFloat(Edit1.Text);

 

h:=0;

Рис. 8.3

 

n:= Memo1.Lines.Count; //определение числа элементов в массиве

for i:=1 to n do

begin //начало тела цикла

{считывание i-го элемента в память из i 1-ой строки компонента Memo1, т.к. нумерация строк в Memo от нуля}

if x[i]<0 then begin //начало действий в случае отрицательного элемента

x[i]:=k*x[i];

h:=h+1;

end; //конец действий для отрицательного элемента

Label3.Caption:=Label3.Caption+#13+FloatToStr(x[i]); {вывод i-го

элемента на отдельной строке с сохранением выведенных ранее элементов} end; //конец тела цикла

Label4.Caption:='отриц. эл-ов '+IntToStr(h);

end;

В случае вывода элементов в компонент Memo2 нужно записать

Memo2.Lines[i-1]:= FloatToStr(x[i]) + #10;

Отметим, что при работе приложения (рис. 8.3) память была от-

ведена при компиляции под сто элементов массива, а реально исполь-

зовалась только под девять, что нерационально.

97

Динамические массивы

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

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

можно ориентироваться на какое-то предельное число. Однако если реальное число элементов окажется больше, то приложение исполь-

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

Для рационального использования памяти при работе с масси-

вами используют динамические массивы. В отличие от обычных (ста-

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

ментов становится известно. Для выделения памяти вызывают проце-

дуру SetLength( имя_массива , число элементов ); например,

var x:array of real; //объявляется динамический веществ. массив

n:byte;

begin //раздел операторов

………… //какие-то вычисления до работы с массивом

n:=….. //вычисление количества элементов по ходу работы программы

SetLength(x, n);//выделение памяти под массив сколько и когда нужно

………….//ввод элементов и какие-то действия с массивом

SetLength(x, 0); //высвобождение памяти

…………..//какие-то вычисления, программа ещё работает

end;

98

Под эффективным использованием памяти понимают, что памя-

ти выделяется ровно столько, сколько нужно, и ровно в те моменты работы программы, когда это нужно.

Нижний индекс динамического массива всегда равен нулю,

верхний можно определить функцией High( имя_массива ), её зна-

чение равно числу элементов в массиве минус единица.

Подпрограмма с открытым параметром-массивом

Над массивами часто выполняются типовые для них действия

(поиск максимального элемента, вычисление суммы элементов и т.д.).

В связи с этим целесообразно типовые действия оформлять в виде пользовательских подпрограмм. При описании пользовательской подпрограммы целесообразно в списке формальных параметров у па-

раметра-массива не указывать число элементов, т.е. использовать от-

крытый параметр-массив. Это позволит подпрограмме обрабатывать массивы любой длины, передаваемые ей целиком в качестве фактиче-

ского массива. Должны лишь совпадать типы элементов формального открытого параметра-массива и фактического массива.

Как и обычные параметры подпрограмм, параметры-массивы могут быть параметрами-значениями (по умолчанию они таковые и есть) или параметрами-переменными. Во втором случае перед пара-

метром-массивом должно стоять слово var. Первые передают массив только в подпрограмму, вторые и обратно. Примеры заголовков

procedure ar (t: array[1..5] of real); //обычный массив, параметр-значение procedure ar (t: array of real); //открытый массив, параметр-значение function ar (t: array of real):real; //открытый массив, параметр-значение procedure ar (var t: array of real); //открытый массив, параметр-переменная

99

Пример 8.2

Разработаем проект для ввода двух массивов из компонентов

Memo и вычисления произведения элементов каждого из них.

Заранее неизвестно какое число элементов введёт пользователь в компоненты Memo, это значит, что следует объявить оба массива динамическими и выделить под них память, когда число элементов в каждом массиве станет известно, т.е. уже по ходу работы приложе-

ния. Это позволит эффективнее расходовать память.

Над обоими массивами выполняется одно и то же действие

налицо целесообразность оформить его в виде подпрограммы. Уже

отметили, что число элементов в массивах на стадии разработки про-

екта неизвестно, да и количество элементов в них наверняка будет

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

подпрограммы использовать открытый параметр-массив, причём он

 

начало

 

 

будет параметром-значением, т.к. массив нужно

 

 

 

 

 

 

 

 

передавать только в подпрограмму, а возвра-

 

P = 1, k = 0

 

 

щать обратно подпрограмма будет отдельное

 

 

 

 

число значение произведения элементов пере-

 

k число

нет

 

данного ей массива. Блок-схема алгоритма вы-

 

 

 

 

э-ов 1

 

 

 

 

да

 

 

числения произведения, реализованная в нашей

 

 

 

 

подпрограмме, изображена на рис. 8.4.

 

P = P·mk

 

 

 

 

 

 

 

 

 

 

Расположим на форме две кнопки Button,

 

 

 

 

связав с ними вычисления произведений для

 

 

 

 

 

k = k + 1

 

 

каждого из массивов. Процессы вычислений

 

 

 

 

 

 

 

 

произведений идентичны для обоих массивов,

 

 

 

 

 

конец

 

 

поэтому приведём одну блок-схему (рис. 8.5).

 

Рис. 8.4

 

 

 

100