|
|||||||
АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомДругоеЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция |
Массивы
До сих пор мы рассматривали переменные, которые имели только одно значение, могли содержать в себе только одну величину определенного типа. Исключением являлись лишь строковые переменные, которые представляют собой совокупность данных символьного типа, но и при этом мы говорили о строке, как об отдельной величине. Вы знаете, что компьютер предназначен в основном для облегчения работы человека с большими информационными объемами. Как же, используя только переменные известных вам типов, сохранить в памяти и обработать данные, содержащие десяток, сотню, тысячу чисел или, к примеру, строк? А ведь такие задачи встречаются в любой области знания. Конечно, можно завести столько переменных, сколько данных, можно даже занести в них значения, но только представьте, какой величины будет текст такой программы, сколько времени потребуется для его составления, как много места для возможных ошибок? Естественно, об этом задумывались и авторы языков программирования. Поэтому во всех существующих языках имеются типы переменных, отвечающие за хранение больших массивов данных. В языке Паскаль они так и называются: "массивы". Массивом будем называть упорядоченную последовательность данных одного типа, объединенных под одним именем. Кстати, под это определение подходит множество объектов из реального мира: словарь (последовательность слов), мультфильм (последовательность картинок) и т. д. Проще всего представить себе массив в виде таблицы, где каждая величина находится в собственной ячейке. Положение ячейки в таблице должно однозначно определяться набором координат (индексов). Самой простой является линейная таблица, в которой для точного указания на элемент данных достаточно знания только одного числа (индекса). Мы с вами пока будем заниматься только линейными массивами, так как более сложные структуры строятся на их основе. Описание типа линейного массива выглядит так: Туре <Имя типа>=Аггау [<Диапазон индексов>] Of <Тип элементов>; В качестве индексов могут выступать переменные любых порядковых типов. При указании диапазона начальный индекс не должен превышать конечный. Тип элементов массива может быть любым (стандартным или описанным ранее). Описать переменную-массив можно и сразу (без предварительного описания типа) в разделе описания переменных: Var <Перемемная-массив>: Array [<Диапазон индексов>] Of <Тип элементов>; Примеры описания массивов: Var S, ВВ: Array [1..40] Of Real; N: Array ['A'.-'Z'] Of Integer; R: Array [-20..20] Of Word; T: Array [1..40] Of Real; Теперь переменные S, ВВ и Т представляют собой массивы из сорока вещественных чисел; массив N имеет индексы символьного типа и целочисленные элементы; массив R может хранить в себе 41 число типа Word. Единственным действием, которое возможно произвести с массивом целиком - присваивание. Для данного примера описания впоследствии допустима следующая запись: S:=BB; Однако, присваивать можно только массивы одинаковых типов. Даже массиву Т присвоить массив S нельзя, хотя, казалось бы, их описания совпадают, произведены они в различных записях раздела описания. Никаких других операций с массивами целиком произвести невозможно, но с элементами массивов можно работать точно также, как с простыми переменными соответствующего типа. Обращение к отдельному элементу массива производится при помощи указания имени всего массива и в квадратных скобках - индекса конкретного элемента. Например: R[10] - элемент массива R с индексом 10. Фундаментальное отличие компонента массива от простой переменной состоит в том, что для элемента массива в квадратных скобках может стоять не только непосредственное значение индекса, но и выражение, приводящее к значению индексного типа. Таким образом реализуется косвенная адресация: ВВ[15] - прямая адресация; ВВ[К] - косвенная адресация через переменную К, значение которой будет использовано в качестве индекса элемента массива ВВ. Такая организация работы с такой структурой данных, как массив, позволяет использовать цикл для заполнения, обработки и распечатки его содержимого. Если вы помните, с такой формой организации данных мы встречались, когда изучали строковые переменные. Действительно, переменные типа String очень близки по своим свойствам массивам типа Char. Отличия в следующем: строковые' переменные можно было вводить с клавиатуры и распечатывать на экране (с обычным массивом это не проходит); длина строковой переменной была ограничена 255 символами (255 В), а для размера массива критическим объемом информации является 64 КВ. Теперь рассмотрим несколько способов заполнения массивов и вывода их содержимого на экран. В основном мы будем пользоваться числовыми типами компонент, но приведенные примеры будут справедливы и для других типов (если они допускают указанные действия). Program Ml; Var А: Array [1..20] Of Integer; Begin A[l]:=7; (Заполняем массив значениями (отдельно каждый компонент)} А[2]:=32; А[3]:=-70;.............. {Трудоемкая задача?} А[20]:=5б; Writeln(A[l],А[2],А[3],?,А[20]) End. Как бы ни был примитивен приведенный пример, он все же иллюстрирует возможность непосредственного обращения к каждому элементу массива отдельно. Правда, никакого преимущества массива перед несколькими простыми переменными здесь не видно. Поэтому - другой способ: Program M2; Var А: Array [1..20] Of Integer; I: Integer, Begin {Организуем цикл с параметром I по всем возможным значениям индексов и вводим с клавиатуры } For I:=l То 20 Do Readln(A[I]); A[I]) {Распечатываем массив в обратном порядке} For I:=20 Downto I Do Write(A[I],'VVV') End. Эта программа вводит с клавиатуры 20 целых чисел, а затем распечатывает их в обратном порядке. Теперь попробуйте написать такую же программу, но без использования структуры массива. Во сколько раз она станет длиннее? Кстати, введение в язык Паскаль цикла с параметром было обусловлено во многом необходимостью обработки информационных последовательностей, т. е. массивов. Следующая программа заполняет массив значениям квадратов индексов элементов: Program МЗ; Const N=50; {Константа N будет содержать кол-во элементов массива} Var А: Array [1..N] Of Integer; I: Integer; Begin For I:=l To N Do A[I]:=I*I For I:=l To N Do Write (A[I], ' ') End. В дальнейшем для учебных целей мы будем использовать массивы, заданные с помощью генератора случайных чисел. В языке Паскаль случайные числа формирует функция Random. Числа получаются дробными, равномерно расположенными в интервале от 0 до 1. Выражение, дающее целое случайное число в интервале [-50,50] будет выглядеть так: Trunc(Random*101)-50 Зададим и распечатаем случайный массив из сорока целых чисел: Program M4; Const N=4 0; {Константа N будет содержать количество элементов массива} Var А: Array [1..N] Of Integer; I: Integer; Begin For I:=l To N Do Begin A[I]:= Trunc(Random*101)-50 Write (A[I], 'VVV) End End. С обработкой линейных массивов связано множество задач. Их мы рассмотрим на практических занятиях. Двумерные и многомерные массивы. Представьте себе таблицу, состоящую из нескольких строк. Каждая строка состоит из нескольких ячеек. Тогда для точного определения положения ячейки нам потребуется знать не одно число (как в случае таблицы линейной), а два: номер строки и номер столбца. Структура данных в языке Паскаль для хранения такой таблицы называется двумерным массивом. Описать такой массив можно двумя способами: I. Var А: Array [1..20] Of Array [1..30] Of Integer; II. Var A: Array [1..20,1..30] Of Integer; В обоих случаях описан двумерный массив, соответствующий таблице, состоящей из 20 строк и 30 столбцов. Приведенные описания совершенно равноправны. Отдельный элемент двумерного массива адресуется, естественно, двумя индексами. Например, ячейка, находящаяся в 5-й строке и 6-м столбце будет называться А[5][б] или А[5,6]. Для иллюстрации способов работы с двумерными массивами решим задачу: "Задать и распечатать массив 10X10, состоящий из целых случайных чисел в интервале [1,100]. Найти сумму элементов, лежащих выше главной диагонали." При отсчете, начиная с левого верхнего угла таблицы, главной будем считать диагональ из левого верхнего угла таблицы в правый нижний. При этом получается, что элементы, лежащие на главной диагонали будут иметь одинаковые индексы, а для элементов выше главной диагонали номер столбца будет всегда превышать номер строки. Договоримся также сначала указывать номер строки, а затем - номер столбца. Program M5; Var А: Array[1..10,1..10] Of Integer; I, К: Byte; S: Integer; Begin S:=0; For I:=l To 10 Do Begin For K:=l To 10 Do Begin A[I,K]:=Trunc(Random*100)+l; Write(A[I,K]:6); If K>I Then S:=S+A[I,K] End; Writeln End; Writeln('Сумма элементов равна ',S) End. Если модель данных в какой-либо задаче не может свестись к линейной или плоской таблице, то могут использоваться массивы произвольной размерности. N-мерный массив характеризуется N индексами. Формат описания такого типа данных: Туре <Имя типа>=Аггау[<диапазон индекса1>, <диапазон индекса2>,...<диапазон индекса N>] Of <тип компонент>; Отдельный элемент именуется так: <Имя массива>[<Индекс1>,<Индекс2>,...,<ИндексN>] Процедуры и функции. При решении сложных объемных задач часто целесообразно разбивать их на более простые. Метод последовательной детализации позволяет составить алгоритм из действий, которые, не являясь простыми, сами представляют собой достаточно самостоятельные алгоритмы. В этом случае говорят о вспомогательных алгоритмах или подпрограммах. Использование подпрограмм позволяет сделать основную программу более наглядной, понятной, а в случае, когда одна и та же последовательность команд встречается в программе несколько раз, даже более короткой и эффективной. В языке Паскаль существует два вида подпрограмм: процедуры и функции, определяемые программистом. Процедурой в Бейсике называется именованная последовательность инструкций, реализующая некоторое действие. Функция отличается от процедуры тем, что она должна обязательно выработать значение определенного типа. Процедуры и функции, используемые в программе, должны быть соответствующим образом описаны до первого их упоминания. Вызов процедуры или функции производится по их имени. Подпрограммы в языке Паскаль могут иметь параметры (значения, передаваемые в процедуру или функцию в качестве аргументов). При описании указываются так называемые формальные параметры (имена, под которыми будут фигурировать передаваемые данные внутри подпрограммы) и их типы. При вызове подпрограммы вместе с ее именем должны быть заданы все необходимые параметры в том порядке, в котором они находятся в описании. Значения, указываемые при вызове подпрограммы, называются фактическими параметрами. Формат описания процедуры: Procedure <Имя процедуры> (<Имя форм, параметра 1>:<Тип>; < Имя форм. Параметра 2>:<Тип>;); <Раздел описаний> Begin <Тело процедуры> End; Раздел описаний может иметь такие же подразделы, как и раздел описаний основной программы (описание процедур и функций - в том числе). Однако все описанные здесь объекты "видимы" лишь в этой процедуре. Они здесь локальны также, как и имена формальных параметров. Объекты, описанные ранее в разделе описаний основной программы и не переопределенные в процедуре, называются глобальными для этой подпрограммы и доступны для использования. Легко заметить схожесть структуры программы целиком и любой из ее процедур. Действительно, ведь и процедура и основная программа реализуют некий алгоритм, просто процедура не дает решения всей задачи. Отличие в заголовке и в знаке после End. Формат описания функции: Function <Имя функции> (список формальных параметров) <Тип функции>; <Раздел описаний> Begin <Тело функции> End; В теле функции обязательно должна быть хотя бы команда присвоения такого вида: <Имя функции>:=<Выражение>; Указанное выражение должно приводить к значению того же типа, что и тип результата функции, описанный выше. Вызов процедуры представляет в программе самостоятельную инструкцию: ■ <Имя процедуры>(список факт. параметров) Типы фактических параметров должны быть такими же, что и у соответствующих им формальных. Вызов функции должен входить в выражение. При вычислении значения такого выражения функция будет вызвана, действия, находящиеся в ее теле, будут выполнены, в выражение будет подставлено значение результата функции. Приведем простейший пример использования подпрограммы. Задача: "Найти максимальное из трех введенных чисел". Для решения воспользуемся описанием функции, принимающей значение максимального из двух чисел, которые передаются в нее в виде параметров.
Program Fn; Var A,B,C:Real; Function Max(А,В:Real):Real; {Описываем функцию Max с формальными параметрами А и В, которая принимает значение максимального из них} Begin If A>B Then Max:=A Else Мах:=В {Здесь А и В - локальные переменные} End; Begin Writeln('Введите три числа'); Readln(А,В,С); Writeln('Макссимум =',Мах(Мах(А,В),С)) End. Обратите внимание на краткость тела основной программы и на прозрачность действий внутри функции. Формальные параметры А и В, используемые в подпрограмме, не имеют никакого отношения переменным А и В, описанным в основной программе. Существует дв~ способа передачи фактических параметров в подпрограмму: по значению и по ссылке. В первом случае значение переменной-фактического параметра при вызове подпрограммы присваивается локальной переменной, являющейся формальным параметром подпрограммы. Что бы потом ни происходило с локальной переменной, это никак не отразится на соответствующей глобальной. Для одних задач это благо, но иногда требуется произвести в подпрограмме действия над самими переменными, указанными в качестве фактических параметров. На помощь приходит второй способ. Происходит следующее: при обращении к подпрограмме не происходит формирования локальной переменной-формального параметра. Просто на время выполнения подпрограммы имя этой локальной переменной будет указывать на ту же область памяти, что и имя соответствующей глобальной переменной. Если в этом случае изменить локальную переменную, изменятся данные и в глобальной. Передача параметров по ссылке отличается тем, что при описании подпрограммы перед именем переменной-формального параметра ставится служебное слово Var. Теперь использование в качестве фактических параметров выражений или непосредственных значений уже не допускается -они должны быть именами переменных. Еще один классический пример. Задача: "Расположить в порядке неубывания три целых числа". Program Pr; Var S1,S2,S3:Integer; Procedure Swap(Var A,B: Integer);{Процедура Swap с параметрами-переменными} Var С: Integer; {С - независимая локальная переменная} Begin {Меняем местами содержимое А и В} С:=А; А:=В; В:=С End; Begin Writeln('Введите три числа'); Readln(Sl,S?,S3); If S1>S2 Then Swap(S1,S2); If S2>S3 Then Swap(S2,S3); If S1>S2 Then Swap(S1,S2); Writeln(в порядке неубывания: ',S1,S2,S3) End. Поиск по сайту: |
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Студалл.Орг (0.012 сек.) |