Лабораторная работа № 4. Работа с одномерными массивами
Работа с одномерными массивами
(подсчет, поиск элементов, перестановки в массиве)
Задачи лабораторной работы
Вопросы, изучаемые в работе
- Изучение простейших составных данных – одномерных массивов.
- Освоение форматного вывода одномерных массивов разных типов.
- Создание и использование в программах входных текстовых файлов с данными.
- Вывод результатов работы в выводной текстовый файл (протокол работы).
- Дальнейшее изучение основных элементарных алгоритмов.
Задание (общее ко всем вариантам)
Составить программу обработки одномерного массива заданного типа произвольной длины. Количество используемых данных должно вводиться с клавиатуры (в пределах отведенного под массив места). Значения элементов массива вводятся или с клавиатуры, или из предварительно созданного текстового файла (в соответствии с заданием). Исходный массив и результаты его обработки выводить в выводной текстовый файл.
Оформить отчет по работе, аналогично отчету по работе № 3, но в печатном виде должны быть представлены текст программы и результаты работы.
Требования к программе
· Если специально не указано, что данные в массив вводятся с клавиатуры, перед запуском программы необходимо подготовить данные требуемого типа в отдельном текстовом файле, которому следует присвоить имя, совпадающее с именем файла Паскаль-программы, но с расширением ".DAT". Данные набивать, отделяя друг от друга пробелом, по 10 – 20 чисел в строке. Для символьных данных – все набивать в одной строке.
· Программа должна обрабатывать данные указанного типа в количестве до 50 чисел и до 250 символов, если количество не указано в задании. Конкретный размер массива при запуске программы вводить с клавиатуры.
· Все значения, на которые по смыслу накладываются ограничения, должны при вводе контролироваться.
· Вывод исходных данных и результатов производить в выходной текстовый файл. При выводе использовать длину выводимой строки не более 76 символов.
Содержание программы
- Заголовок программы с комментарием;
- Описание переменных и массива;
- Описание меток;
- Ввод исходных данных с клавиатуры;
- Открытие входного и выводного файлов;
- Заполнение массива из файла;
- Вывод на печать введенного массива в выводной файл под заголовком "Исходные данные";
- Проведение обработки массива в соответствии с заданием;
- Вывод результатов обработки в выводной файл под заголовком "Результаты расчета";
- Закрытие всех файлов.
Общие пояснения
Рассмотрим некоторые моменты, связанные с обработкой одномерных массивов. Следует помнить, что выделение памяти под массив при его описании может производиться только с помощью констант (в явном виде, или с предварительным описанием константы), например:
Const MIN=5;
MAX=100;
Var Massiv1 : array[1..110] of real;
Massiv2 : array[MIN..MAX] of integer;
Кроме того, рекомендуется сначала завести свои описатели типов массивов, а затем с их помощью выделять место под конкретные переменные этих "массивных" типов, например:
Const MAXI=200;
Type IntMasMAX = array[1..MAX] of integer; {описатель для целочисленных массивов из MAX элементов}
RealMass = array[1..110] of real; { описатель
для вещественных массивов из 110 элементов }
Var Massiv1,Nmbs:IntMasMAX; {завели 2 целочисл. массива}
Massiv2,WindV:RealMass; {Завели 2 веществ. массива}
Программы, использующие массивы, позволяют сначала ввести все необходимые данные, а только потом их использовать. Поэтому в таких программах следует предусматривать следующие шаги (в указанном порядке):
1. Ввод исходных данных. Обычно включает ввод количества элементов массива (с проверкой допустимости введенного значения) и ввод самих элементов массива в указанном количестве. Если ввод значений предусмотрен с клавиатуры, перед каждым оператором чтения должен быть запрос на ввод. Если используется ввод из файла, запросы не делаются, но перед вводом данных в массив из файла, последний следует открыть для чтения стандартными процедурами Assign и Reset, а в разделе описаний переменных для файла должна быть введена переменная с помощью описателя text:
VAR
Finput : text; {завели файловую переменную для набора данных текстового типа}
. . .
BEGIN
. . .
Writeln(' Введи длину массива');
metka: Read(N);
if(N<MIN) or (N>MAX) then
Begin
Writeln('Недопустимое количество, введите снова');
goto metka;
End;
Assign(Finput,'UMNIK4.DAT'); { связали файловую
переменную с набором данных UMNIK4.DAT }
Reset(Finput); { открыли файл для чтения }
for i:=1 to N do
Read(Finput,Massiv2[i]);
. . .
Если в задании требуется вводить данные в массив, пока не встретится определенный признак, то можно поступить двумя способами. Организовать арифметический цикл со счетчиком от одного до предельно-допустимой длины массива и дополнительным выходом из цикла, если встретился признак; или использовать итеративный цикл с условием продолжения, если введенное значение – не признак, и его порядковый номер меньше длины массива.
2. Вывод исходных данных. Включает обычно вывод заголовка массива, возможно с указанием его длины, и затем вывод заполненных элементов массива в удобной для просмотра на экране (и при распечатке) форме. При выводе на дисплей можно ориентироваться на ширину экрана (80 позиций), при печати – на 60 (вдоль тетрадного листа), 76 (поперек тетрадного листа или при выводе на стандартный лист).
Обычно для распечатки результатов работы используют вывод в текстовый файл, который затем выводят на принтер, как и текст программы. Чтобы вывод выполнять в файл, необходимо предусмотреть в программе следующие шаги:
· в разделе описаний переменных завести файловую переменную типа text для вывода;
· в выполняемом блоке связать файловую переменную с набором данных и открыть для вывода (используя стандартные процедуры Assign и ReWrite);
· в операторах Write и WriteLn в качестве первого (или единственного) параметра указывать имя файловой переменной;
· перед концом программы закрыть выводной файл стандартной процедурой Close.
Оформление вывода следует выполнять с использованием формата, размер которого определяется максимальными размерами выводимых значений.
Например, если числа целые и находятся в диапазоне от –999 до +999, формат должен быть не менее :5 (с учетом разделяющих пробелов). Если диапазон целых чисел неизвестен, следует рассчитывать на максимум. Для самых длинных целых чисел (–32768) он составит :7 и выводить удобно по 10 значений в строке.
Для вещественных чисел, если использовать экспоненциальную форму записи, достаточно оставлять три значащие цифры, что с учетом знака, точки и порядка числа составит :11, например, _–0.836Е-02, и выводить имеет смысл по пять чисел в строке.
Конечно, удобнее числа выводить в форме с фиксированной точкой (что можно делать, если порядки чисел известны и они не сильно отличаются от нулевого). Например, по формату :8:2 вывод идет с точностью до сотых.
При выводе в конце каждой строки следует давать команду Writeln для перехода на новую строку. Определить, что пора менять строку, можно по остатку от деления текущего номера элемента на количество значений в строке. Ниже приведен пример вывода на печать в выводной текстовый файл Fout одномерного вещественного массива по "k" значений в строке:
Assign(Fout,'UMNIK4.RES'); {связали Fout с Н.Д. UMNIK4.RES }
ReWrite(Fout); { открыли файл для записи }
Writeln(Fout,' Исходный массив из ',N,' элементов');
for i:=1 to N do
Begin
Write(Fout,Massiv2[i]:8:2); { печать в текущей строке}
if i mod k = 0 then Writeln(Fout); {если номер элемента
кратен "к", переходим на новую строку}
End;
. . .
Close(Fout); {закрытие файла }
3. Обработка массива. Здесь могут встретиться различные ситуации, на которые следует обратить внимание.
а) Если в задаче предлагается использовать признак делимости на некоторое число значения переменной (например, требуется что-то делать с каждым элементом массива, который нацело делится на 5), то следует в цикле брать каждый элемент, и проверять на равенство нулю остатка от деления значения элемента массива на 5:
for i:=1 to N do
begin
if K[i] mod 5 = 0 then
{ делать что надо, т.к. элемент массива делится на 5} ;
. . .
end;
б) Если же предлагается использовать признак делимости номера элемента, то разумнее сначала вычислить количество выбираемых номеров и организовать цикл по вычисленному количеству, каждый раз определяя, какой элемент массива надо обрабатывать.
Например, если надо что-то делать с каждым пятым элементом массива К длиной N элементов, то цикл обработки будет иметь вид:
M:=N div 5; { определение числа повторений цикла }
for i:=1 to M do
begin
j:=i*5; { определение номера обрабатываемого элемента}
{ обработка K[j]-го элемента массива }
. . .
end;
Если нужно обрабатывать каждый пятый элемент, начиная с третьего, программа будет выглядеть по-другому:
j:=3;
M:=(N-(3-1)) div 5;{определение числа повторений цикла}
for i:=1 to M do
begin { обработка K[j]-го элемента массива }
. . .
j:=j+5; {определение номера следующего обраб.элемента}
end;
в) Если требуется обрабатывать символьный массив, например, подсчитать, сколько раз встречается символ 'Ó', нужно уметь, во-первых, присваивать символьным переменным нужные значения, во-вторых, вводить символы в массив с клавиатуры, и, в-третьих, уметь сравнивать символьные элементы массива.
Присваивание значения переменной можно сделать либо перенося это значение из другой переменной (если она содержит в данный момент нужный символ), либо задавая присваивание константы, либо используя функцию Chr(i), преобразования целого числа в символ (с кодом, равным этому числу). Таблица кодов символов приведена в Приложении Г. Примеры присваивания:
Const
SimA ='A';
Paragraf = #21;
Kod = 21;
SixKod = $15;
Var S1,S2,S,S4,S5,S6 : char;
. . .
Begin
. . .
S1:= SimA;
S2:=S1;
S3:='A';
S3:=Paragraf;
S4:=#21;
S5:=#$15;
S6:=Chr(21);
S7:=Chr($15);
Пример используемых операторов:
. . .
Var Sim : char;
TextM:array[1..100] of char;{завели символьный массив}
i,N : shortint;
. . .
Begin
. . .
{Если заполнение символьного массива TextM с клавиатуры}
for i:=1 to N do
begin
writeln('Вводи очередной символ');
readln(TextM[i]);
end;
. . .
{Если заполнение символьного массива TextM из файла}
assign(fin,'UMNIK4.DAT');
reset(fin);
for i:=1 to N do
read(fin,TextM[i]);
. . .
close(fin); { не забыть в конце закрыть все открытые файлы }
4. Вывод результатов. Если в процессе выполнения программы исходный массив изменяется (в нем меняются сами значения элементов, их количество или они переставляются), исправленный массив должен выводиться в конце программы под заголовком 'Измененный массив'.
Разбор контрольного варианта
Задание.
Таблица 16. Данные к заданию 31 варианта
№ вар. | Задание | Печатать элементы массива по | Тип обрабат. данных | |
штук: | формату: | |||
Формирование символьного массива длиной не более ста элементов, заполнение его с клавиатуры (вводя по одному произвольному символу пока не встретится символ "."), подсчет и вывод на экран символа, который встретился чаще других и число его повторений. | :2 | Символьный |
При решении этой задачи нужно выделить место на символьный массив из ста элементов, заполнить его (в итеративном цикле – пока не встретится символ '.' или не введется сто символов), распечатать его (по 30 символов в строке) и провести подсчеты частоты вхождения каждого символа. Последняя часть представляет наибольшую сложность, поэтому остановимся на ней подробнее.
Так как нужно найти самый частый символ и количество его повторений, необходимо в программе завести переменные символьного типа для рассматриваемого символа (SimI) и для самого частого символа (SimMax), а также счетчики для рассматриваемого (Ni) и самого частого (Nmax) символов. В качестве SimI будем брать по очереди каждый символ из массива (во внешнем цикле по i – номеру в массиве длиной N элементов) и для него считать, сколько раз этот символ встречается в массиве (внутренний цикл по j – для всех элементов массива). Если после подсчета Ni окажется больше Nmax, значение Ni переносится в Nmax, а SimI – в SimMax.
Очевидно, перед внешним циклом Ni следует обнулить, а в SimMax занести, например, первый элемент символьного массива.
Длина массива N подсчитывается один раз при заполнении массива (и не может превышать 250).
Понятно, что данный алгоритм не самый эффективный, так как любой символ, встречающийся несколько раз, мы будем обсчитывать столько раз, сколько он встречается. Но пренебрежение этим обстоятельством позволит существенно упростить алгоритм, так как не нужно запоминать и каждый раз в начале тела внешнего цикла проверять, какие символы мы уже обсчитали.
Для разбираемого варианта не приводятся таблица идентификаторов и блок-схема алгоритма, хотя при оформлении лабораторной работы их следует включить в отчет.
С учетом выполненного выше разбора задачи, программа может иметь вид:
Текст программы
PROGRAM Simbol_Array;
{ Программа Лабораторной работы N 4
Вариант N 31.
гр. Я-007, ст. А.Я. Умненькая }
VAR
N,Ni,Nmax,i,j :integer;
SimI,SimMax :char;
Simbol :array[1..100] of char;
Fout :text;
BEGIN {Выполняемый блок. Первый раздел – ввод данных }
N:=0;
writeln('Вводить по одному не более 100 символов,');
writeln(' Для завершения – ввести символ "."');
repeat
writeln('Введи очередной символ');
N := N + 1;
readln(Simbol[N]);
until (N = 100) or (Simbol[N] = '.');
if Simbol[N]= '.' then N := N - 1; { Последний символ, если он – точка, рассматриваться не будет }
if N < 1 then
writeln('Нельзя рассматривать меньше 1 символа')
else
begin
Assign(Fout,'UMNIK4.RES'); {связали Fout с UMNIK.DAT}
ReWrite(Fout); {открыли файл для записи }
writeln(Fout,'Исходный массив из ',N,' элементов');
for i:=1 to N do
begin
write(Fout,Simbol[i]:2); { печать в текущей строке}
if i mod 30 = 0 then writeln(Fout); { если номер
элемента кратен 30 переходим на новую строку}
end;
writeln(Fout);
{ Основной раздел – поиск номера }
Nmax := 0; { количество наиболее частого символа }
SimMax := Simbol[1];
for i:=1 to N do { внешний цикл перебора символов }
begin
SimI := Simbol[i];
Ni := 0;
for j:=i to N do { внутренний цикл перебора символов }
if Simbol[j] = SimI then Ni:=Ni+1;
if Ni>Nmax then {если этот символ встретился чаще,}
begin {запомним его и число его вхождений}
Nmax := Ni;
SimMax := SimI;
end;
end;
{ Раздел вывода результатов поиска }
if Nmax = 1 then
writeln(Fout,'Все символы входят по 1 разу')
else
write(Fout,'Символ "',SimMax,'" встретился ',Nmax,
' раз');
{ далее определим, если Nmax кончается на 2,3,4 и не во втором десятке, изменим окончание, например, "23 раза" }
if (Nmax mod 10 < 5) and (Nmax mod 10 > 1) and
(Nmax div 10 <> 1)
then writeln(Fout,'а');
end;
Close(Fout);
END.
Результаты работы
(содержимое файла UMNIK.RES)