
- •От автора
- •1. Общая схема решения задачи на персональном компьютере
- •2. Структура программы на языке Паскаль
- •3. Арифметические типы данных. Числовые константы и переменные. Оператор присваивания. Выражение
- •4. Операторы ввода-вывода
- •5. Арифметические операции. Стандартные математические функции
- •6. Символьный тип данных
- •7. Логический тип данных. Операции сравнения. Логические операции
- •8. Условный оператор. Блок. Оператор выбора
- •9. Операторы цикла
- •10. Метки. Оператор Goto. Процедура Halt
- •11. Интервальные типы данных. Оператор Type. Массивы
- •Var a : Array[1..33000] Of Word;
- •Var a : Array[1..3] Of Real;
- •Var e,f : Massiv;
- •Var a : Array[1..10] Of Array[1..20] Of Real;
- •12. Процедуры и функции. Сфера действия описаний
- •13. Открытые массивы и нетипизированные параметры
- •14. Множества
- •15. Тип String
- •16. Графические средства языка Паскаль
- •17. Особенности вещественных вычислений
- •18. Записи
- •19. Тип "перечисление"
- •20. Модуль Crt
- •Var TextAttr : Byte
- •21. Модули. Создание и использование модулей
- •Interface
- •Implementation
- •22. Файлы
- •23. Другие средства обработки файлов и модуль dos
- •24. Процедурные типы
- •25. Указатели и динамическая память
- •26. Динамические структуры: списки, деревья
- •27.Открытые строки
- •28. Использование командной строки и вызов внешних программ
- •29. Обработка программных прерываний
- •30. Объекты
- •31.Рекурсия и динамическое программирование
- •32. Рекурсия и стек отложенных заданий
- •33. Стеки и очереди
- •34. Комбинаторные алгоритмы
- •35. Бинарные деревья
- •36. Упорядоченные бинарные деревья и приоритетные очереди
- •37. Алгоритмы сортировки
- •38. Графы
- •Рекомедуемая литература
- •Содержание
Var a : Array[1..33000] Of Word;
Больше никаких ограничений на тип индекса не накладывается. Все описанные в программе простые переменные и массивы размещаются в специальной области памяти, называемой сегментом данных. Размер сегмента данных никогда не может превосходить 64 К байт, поэтому, описывая очень большой массив, следует задуматься - а где разместятся остальные переменные? Такое ограничение на размер сегмента данных является очень жестким, так как очень часто программе требуется намного больше памяти; как обойти это ограничение, мы обсудим позже.
Тип элементов массива может быть любым - целочисленным, вещественным, символьным, логическим, интервальным. Элементы массива могут быть массивами, тогда вы получите массив размерностью больше, чем 1. Опишем несколько массивов :
Var a : Array[Char] Of 1..5; - массив из 256 элементов, каждый из которых есть целое число от 1 до 5, индексы элементов изменяются от #0 до #255;
Const Max = 99;
Min = 10;
Type Nums = Min..Max;
Type ArrayType = Array[-10..0] Of Nums;
Var a : ArrayType; - массив из 11 элементов с индексами от -10 до 0, каждый элемент - целое положительное число из двух цифр;
Type IndexType = 'a'..'z';
Var a : Array[IndexType] Of Boolean; - массив из 26 элементов с индексами от 'a' до 'z', каждый элемент - логическая переменная.
В программе вы можете использовать массивы как целиком, так и отдельные их элементы. Элемент одномерного массива записывается в виде:
имя массива [ индексное выражение ]
Индексное выражение - это любое выражение соответствующего типа. Если элемент массива - не массив, то с ним можно выполнять любые операции, разрешенные для простых переменных соответствующего типа. Если значение индексного выражения неприемлемо для типа индекса, то происходит уже известная нам ошибка Range check error: пусть, например, массив описан как Var m:Array[-3..7] Of Real; тогда обращение к элементу m[-4] или m[8] вызовет эту ошибку.
Целому массиву (всей совокупности элементов) можно лишь присваивать массив того же типа. Заметим, что, если массивы описаны в программе таким образом
Var a : Array[1..3] Of Real;
b,c,d : Array[1..3] Of Real;
Type Massiv=Array[1..3] Of Real;
Var e,f : Massiv;
g : Massiv;
h,i : Massiv;
то массивы b,c,d - однотипные и массивы e,f,g,h,i тоже однотипные, но массивы a и b (a и c, a и d) имеют разный тип, и массивы b (c,d,a) и e (f,g,h,i) имеют разный тип! Компилятор считает, что две переменные имеют один и тот же тип, только если они описаны в одном операторе через запятую либо имена их типов одинаковы. Запомните это очень важное правило.
Запишем пример программы, использующей (пока одномерные) массивы :
{ программа вводит массив из N целых чисел, где N не превосходит 20, и выводит его в порядке неубывания }
Const Nmax=20;
Type IndexType=1..Nmax;
Massiv=Array[IndexType] Of Integer;
Var a : Massiv;
i,j,N : IndexType;
t : Integer;
Begin
WriteLn;
Repeat
Write('Введите длину массива от 1 до ',Nmax,' ');
Read(N);
WriteLn;
Until (N>=1)And(N<=Nmax);
{ Вводим массив поэлементно }
WriteLn('Введите элементы массива');
For i:=1 To N Do Read(a[i]);
{ Сортируем элементы массива по неубыванию. Используем очень простой, но неэффективный алгоритм сортировки - сравниваем каждый элемент с каждым и, если предыдущий больше последующего, меняем их местами }
For i:=1 To N-1 Do
For j:=i+1 To N Do
If a[i]>a[j] Then Begin
t:=a[i];
a[i]:=a[j];
a[j]:=t;
End;
{ Выводим отсортированный массив поэлементно }
WriteLn('Результат сортировки :');
For i:=1 To N Do Write(a[i]:8);
End.
Обратите внимание на алгоритм перестановки двух элементов массива. Запись a[i]:=a[j]; a[j]:=a[i]; , очевидно, привела бы к неверному результату. Использованный нами алгоритм сортировки (он называется “сортировка обменами”) прост и вполне надежен, но не очень эффективен, так как выполняет много лишних операций. Не составляет труда усовершенствовать его - для каждого i от 1 до N-1 найдем наименьший из элементов ai, ai+1, ... , aN и поместим его на i-е место; такой алгоритм выполняет столько же сравнений, сколько и первоначальный, но требует существенно меньшего количества перестановок, он называется “сортировка выбором”:
For i:=1 To N-1 Do Begin
a_max:=a[i]; n_max:=i;
For j:=i+1 To N Do
IF a[j]<a_max Then Begin a_max:=a[j]; n_max:=j; End;
If n_max<>i Then Begin a[n_max]:=a[i];a[i]:=a_max; End;
End;
Как видите, запись алгоритма несколько длиннее, и потребовались две новые переменные a_max - типа Integer и n_max - типа IndexType. Это действие одного из законов программирования - из двух верных алгоритмов более эффективный, как правило, сложнее. Решим еще одну, более сложную, но и более интересную задачу: даны два упорядоченных массива X1 длиной n1 и X2 длиной n2, требуется объединить эти массивы в массив Y длиной n1+n2, не нарушая упорядоченности. Есть тривиальное, но очень плохое решение этой задачи - дописать массив X2 справа к массиву X1, а затем упорядочить полученный массив. Этот алгоритм неэффективен, так как он не использует упорядоченность массивов X1 и X2. Если мы будем пользоваться сортировкой обменами или сортировкой выбором, то потребуется порядка (n1+n2)2 действий (сравнений и обменов). Гораздо лучше использовать так называемый “алгоритм слияния“, идея которого очень проста: вначале массив Y пуст; если первый элемент X1 меньше, чем первый элемент X2, то “заберем” элемент из X1, в противном случае - из X2. Действительно, если X1[1] меньше, чем X2[1], то он является наименьшим элементом в обоих массивах. Будем поступать таким образом, пока не “заберем” все элементы обоих массивов. Если один из массивов “опустел”, то можно сразу “забрать” весь остаток второго массива. Этот алгоритм требует всего лишь порядка n1+n2 действий, очевидно, что более эффективных алгоритмов не существует (нельзя решить эту задачу, не обратившись хотя бы один раз к каждому из элементов X1 и к каждому из элементов X2, а это как раз n1+n2 действий). Запишем один из вариантов алгоритма слияния.
Const
n1= 100;
n2= 200;
Var
X1 : Array[1..n1] Of Word;
X2 : Array[1..n2] Of Word;
Y : Array[1..n1+n2] Of Word;
j1,j2,n : Word;
Begin
{вычисление элементов массивов X1 и X2}
For j1:=1 To n1 Do X1[j1]:=3*j1;
For j2:=1 To n2 Do X2[j2]:=2*j2;
n:=0; {массив Y пуст}
j1:=1; {текущий элемент массива X1}
j2:=1; {текущий элемент массива X2}
While n<n1+n2 Do Begin
{есть хотя бы один элемент в X1 или X2, так как Y не полон}
Inc(n); {увеличиваем индекс текущего элемента массива Y}
If(j1<=n1)And((j2>n2)Or(j2<=n2)And(X1[j1]<X2[j2]))Then Begin
{массив X1 не пуст и либо массив X2 пуст, либо текущий элемент в X1
меньше, чем текущий элемент в X2, следовательно, берем элемент из X1}
Y[n]:=X1[j1];
Inc(j1);
End
Else Begin
{в остальных случаях берем элемент из X2}
Y[n]:=X2[j2];
Inc(j2);
End;
End;
{выведем массив Y}
For n:=1 To n1+n2 Do Write(Y[n]:4);
End.
Теперь перейдем к рассмотрению многомерных массивов. Размерностью, или количеством измерений, массива называется количество индексов у элемента массива, но не количество элементов в массиве. Мы уже знаем, что элемент массива может быть массивом, поэтому двумерный массив можно описать, например, так :