Динамические массивы
Объявление, выделение памяти
Обычно в языке Паскаль используются статические массивы вида:
var mas: array [1..10] of integer; |
Границы статического массива изменить в ходе программы нельзя, так как они задаются в разделе объявлений «раз и навсегда».
Основным недостатком такого массива является то, что в случае, когда заранее не известно количество элементов массива, то приходится выделять память максимального размера, что называется «на всякий случай».
Рассмотрим работу с динамическим массивом.
Объявляется динамический массив в теле программы:
begin ... var a: array of integer; |
Или объявление с инициализацией:
var a:= Arr(1,3,2,7); |
А выделение памяти и размер такого массива задается уже по ходу программы:
var a: array of integer; var n:=readInteger; a:=new integer[n]; |
var a: array of integer; a:=new integer[readInteger]; |
var a: array of integer; var n:=readInteger; SetLength(a,n); // устанавливаем размер массива а |
Ссылочная объектная модель: память выделяется служебным словом NEW
var a := new integer[5]; |
Инициализация, присваивание и вывод
Возможна инициализация динамического массива при описании:
var a: array of integer := (1,2,3); |
Новые способы заполнения массива (заполнители):
var a:=Arr(1,2,3);// по правой части - integer |
var a:=ArrFill(5,2); // 2 2 2 2 2 |
Ввод с клавиатуры:
var a:=ReadArrInteger(5); var a:=ReadArrReal(5); |
Заполнение случайными числами:
var a:=new integer[10]; a:=arrRandomInteger(10); |
или с дополнительными параметрами (диапазон [5;15]):
var a:=arrRandomInteger(10,5,15); |
Вывод массива
print(a); |
Или с разделителем между элементами:
print(a, '; '); |
Или:
printArr(a); |
Или с использованием метода:
a.Print; // пример вывода: 1 5 3 13 20 a.PrintLines; // каждый элемент с новой строки |
Переприсваивание:
var a: array of integer := (1,2,3); var b:=a; // [1,2,3] |
Но!
Если теперь переприсвоить значение элементов массива b
, то изменится и массив a
:
var a: array of integer := (1,2,3); var b:=a; b[2]:=1; print(a); //[1,2,1] |
Для того, чтобы избежать данной ситуации, необходимо создать массив b
, как копию массива a
:
var a: array of integer := (1,2,3); var b:=Copy(a); b[2]:=1; print(a); //[1,2,3] |
Очистка динамического массива
Если в программе случайно создается повторно один и тот же массив:
var a: array of integer; a:=new integer[4]; ... a:=new integer[5]; |
В результате возникают так называемые участки «утекшей» памяти (неиспользуемой).
Постепенно произойдет переполнение памяти. В платформе .net используется автоматический сборщик мусора.
Но можно очистить память и принудительно:
a:=nil; |
В процессе очистки выполнение программы и всех процессов приостанавливается. По этой причине сборщик мусора в системах реального времени не используется.
Работа с элементами массива
- Цикл for
- Цикл foreach
for var i:=0 to High(a) do print(a[i]);; |
foreach var x in a do print(x); |
High(массив)
— возвращает верхнюю границу динамического массива
Выполнение:
Выполним сначала БЕЗ использования обобщенной функции:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | function IndexOf(a:array of integer;x:integer):integer; begin result:=-1; for var i:=0 to High(a) do if a[i]=x then begin result:=i; break end end; begin var a:=Arr(1,2,3,4,5); print(IndexOf(a,5)) end. |
А теперь, выполним с использованием обобщенной функции:
1 2 3 4 5 6 7 8 | function IndexOf<T>(a:array of T;x:T):integer; begin ... end; begin var a:=Arr(1,2,3,4,5); print(IndexOf(a,5)) end. |
- Автовыведение типа Т, сравнение с реальными цифрами, и т.к. числа целые, то Т определится как integer.
- Берется тело функции и заменяется Т на integer (инстанцирование функции с конкретным типом)
Методы для работы с массивами
Reverse(a)
var a:=Arr(1,2,3,4,5); reverse(a); // [5,4,3,2,1] |
Sort(a)
var a:=Arr(2,3,1,4,5); //[1,2,3,4,5] sort(a); |
SortByDescending(a);
— по убываниюa.Min
a.Max
a.Sum
a.Average
— среднее арифметическое
a.IndexOf(x)
и a.LastIndexOf(x)
:begin var a := new integer[10]; a := arrRandomInteger(5,0,5); //[1,3,5,4,5] print(a.IndexOf(3)) // 1 end. |
или метод a.Contains(x)
наравне с x in a
:
begin var a := new integer[10]; a := arrRandomInteger(5,0,5); //[1,3,5,4,5] print(a.Contains(3)); // True print(3 in a)// True end. |
Некоторые алгоритмы работы с массивами
Стандартное выполнение:
var a:=Arr(1,2,3,4,5,6); var x:=a[0]; for var i:=0 to 4 do a[i]:=a[i+1]; a[5]:=x; print(a) |
// … var v := a[0]; for var i:=0 to a.Length-2 do a[i] := a[i+1]; a[a.Length-1] := v; |
- либо задействовать еще один массив (𝜭 (n-k) — по времени)
- либо много раз запускать один и тот же алгоритм (𝜭 (1) — по памяти)
Решение 1:
// … var (min, minind) := (a[0], 0); for var i:=1 to a.Length-1 do if a[i]<min then (min, minind) := (a[i], i); Result := (min, minind); |
Решение 2:
// … var (min, minind) := (real.MaxValue, 0); for var i:=0 to a.Length-1 do if a[i]<min then (min, minind) := (a[i], i); Result := (min, minind); |
Решение 3:
begin var a := new integer[5]; a := arrRandomInteger(5); // [86,37,41,45,76] print(a.Min,a.IndexMin); // 37 1 end. |
// … var v := a[0]; for var i:=0 to a.Length-2 do a[i] := a[i+1]; a[a.Length-1] := v; |
// … var v := a[a.Length-1]; for var i:=a.Length-1 downto 1 do a[i] := a[i-1]; a[0] := v; |
Срезы
Срез массива — это подмножество исходного массива.
- Срезы доступны только на чтение, присваивать им значения нельзя.
- Тип среза такой же, как у массива.
- Срезы работают с массивами, строками и со списками.
var a:=Arr(1,2,3,4,5,6); print(a[1:5]) // [2,3,4,5] |
a[1:5]
— 1-й элемент включая, 5-й не включая
println(a[:5]); // [1,2,3,4,5] - с начала до 5-го не включая println(a[1:]); // [2,3,4,5,6] - до конца println(a[::2]); // [1,3,5] - третий параметр - это шаг |
a[::-1]
— получим 6 5 4 3 2 1
Т.о. выполнение при помощи срезов выглядит так:
Перестановка:
var a:=Arr(1,2,3,4,5,6); var k:=a.Length-1; // 6 - 1 a:=a[k:]+a[:k]; print(a) // [6,1,2,3,4,5] |
Т.е. создан еще массив уже со сдвигом.
Время работы алгоритма n+n
, 𝜭 (n)
Подробнее со срезами можно ознакомиться здесь
Удаление и вставка элементов массива. Списки
Для расширения массива путем вставки какого-либо элемента, необходимо предусмотреть место в памяти. По этой причине для данных случаев проще использовать списки:
Списки — List
Подробнее со списками можно ознакомиться здесь
Решение задач
Простые задачи
SumArray
, возвращающую сумму элементов заданного динамического массива. Выведите длину и сумму элементов массиваВыполнение:
1 2 3 4 5 6 7 8 | function SumArray(var a: array of integer): integer:=a.Sum; begin var a:=new integer[10]; a:=arrRandomInteger(10); foreach var x in a do print(x); println('длина массива = ',a.Length,' сумма = ',ArraySum(a)) end. |
PrintArr
). Используйте для разделителя delim
значение по умолчанию равное ‘;
‘Выполнение:
Дополните код:
1 2 3 4 5 6 7 8 9 10 | procedure PrintArr( a: array of integer; delim:string:='; '); begin foreach var ... in ... do print(x,delim); end; begin var a:=new integer[10]; a:=arrRandomInteger(10); ... end. |
Написать процедуру для печати значений массива любого типа.
✍ Решение:
procedure printArray<T>(a: array of T); begin for var i:=0 to a.Length-1 do begin print(a[i]); end; println end; |
b
) первыми N
(N ≥ 0
) положительными нечётными числами массива a
. Необходимо реализовать два различных решения задачи:
- Функция
MakeOddArrFunc
с одним параметромN
, возвращающая массив. - Процедура
MakeOddArrProc
с двумя параметрами: входным —массив a
и выходным параметром — массивом положительный нечетных чисел
Фрагмент программы:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | function MakeOddArrFunc (a: array of integer; n:integer):array of integer; begin var b:= new integer[n]; var j:=0; for var i:=0 to ... do if ... then begin ...;...;end; SetLength(...,...); result:=b; end; procedure MakeOddArrProc (a: array of integer;var b: array of integer; n:integer); begin b:= new integer[n]; var j:=0; for var i:=0 to ... do if ... then begin ...;...;end; SetLength(...,...); end; begin var a:=arrRandomInteger(20); var b: array of integer; var n:=readInteger('введите N'); println('исходный массив ',a); println('результат работы с функцией ',MakeOddArrFunc(a,n)); MakeOddArrProc(a,b,n); print('результат работы с процедурой ',b) end. |
N
(N ≥ 0
) числами Фибоначчи. Достаточно одной из реализаций: функции или процедуры Фрагмент программы:
1 2 3 4 5 6 7 8 9 10 11 12 | function MakeFibArr (n : integer):array of integer; begin var c:= new integer[n]; c[0]:=...;c[1]:=...; for var i:=2 to n-1 do ...; result:=c; end; begin var n:= readinteger; ...; end. |
EvenMult
с двумя параметрами: входным (параметр по значению) — целочисленным массивом и выходным (параметр по ссылке) — evensCnt
— значением целого типа, которая увеличивает все элементы массива с чётными значениями в два раза и записывает в evensCnt
количество таких элементовMakeRandomRealArr
с тремя параметрами: целым числом N
(N ≥ 0
), вещественными параметрами a
и b
(a < b
).Функция должна возвращать массив (тип которого либо
RealArr
либо array of real
) из N
случайных вещественных элементов в диапазоне a..b
.Продемонстрируйте заполнение и вывод на экран массива
Выполнение:
1 2 3 4 5 6 7 8 9 10 11 | function MakeRandomRealArr (n : integer;a,b:real):array of real; begin var c:= ArrRandomReal(n,a,b); result:=c; end; begin var n:= readinteger; var a:=readReal; var b:=readReal; println('результат работы с функцией ',MakeRandomRealArr(n,a,b)); end. |
FindMin
.с нечётными индексами (процедура
SetToZeroOddIndexes
).Условный оператор не использовать
Выполнение:
1 2 3 4 5 6 7 8 9 10 11 12 13 | procedure SetToZeroOddIndexes(a: array of integer); begin var j:=0; while j<=a.Length-1 do begin a[j]:=0;j+=2; end; println('результирующий массив: ',a); end; begin var a:=arrRandomInteger(10); println('исходный массив: ',a); SetToZeroOddIndexes(a); end. |
FirstLocMin
.
Пояснение: локальным минимумом считается тот элемент, который меньше каждого из своих соседей. Считать, что локальный минимум в массиве есть. Первый и последний элемент в качестве локальных минимумов не рассматривать.
Задачи на срезы
N
. Вывести его элементы в обратном порядкеA
размера N
и целое число K
(1<=K<=N
). Вывести его элементы с порядковыми номерами, кратными K
:
Ak, A2*k, A3*k...
Условный оператор не использовать.
Выполнение:
1 2 3 4 | var n:=ReadInteger; var a:=ReadArrReal(n); var k:=ReadInteger; a[k-1 : : k].Print; |
A
размера N
(N
- четное число). Вывести его элементы с четными номерами в порядке возрастания номеров:
а2, а4, а6, ... аn
Условный оператор не использовать.
A
размера N
(N
- нечетное число). Вывести его элементы с нечетными номерами в порядке убывания номеров:
аn, аn-2, аn-4, ... а1
Условный оператор не использовать.
A
размера N
. Вывести сначала его элементы с четными номерами (в порядке возрастания номеров), а затем - элементы с нечетными номерами (также в порядке возрастания номеров):
а2, а4, а6,...а1, а3, а5...
Условный оператор не использовать
Выполнение:
1 2 3 4 | var n:=ReadInteger; var a:=ReadArrReal(n); var srez:=a[1::2]+a[::2]; Print(srez); |
A
размера N
. Вывести сначала его элементы с нечетными номерами (в порядке возрастания номеров), а затем - элементы с четными номерами (в порядке убывания номеров):
а1, а3, а5, ..., а6, а4, а2...
Условный оператор не использовать
N
и целые числа K
и L
(1<=K<=L<=N
). Найти среднее арифметическое элементов массива с номерами от K
до L
включительноВыполнение:
1 2 3 4 5 6 | var n:=ReadInteger; var a:=ReadArrReal(n); var k:=ReadInteger; var l:=ReadInteger; var srez:=a[k-1:l].Average; print(srez); |
N
и целые числа K
и L
(1<=K<=L<=N
). Найти сумму элементов массива кроме элементов с номерами от K
до L
включительноА
размера N
. Найти минимальный элемент из его элементов с четными номерами: а2, а4, а6,... .Выполнение:
1 2 3 | var n:=ReadInteger; var a:=ReadArrReal(n); print(a[1::2].min); |
Например:
[1,2,3,4,5,6,7,8] -> [5,6,7,8,1,2,3,4]
Использование методов
System.DateTime.Now
Выполнение:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | function MyMin(a: array of real): integer; begin var minInd:=0; for var i:=1 to a.Length-1 do begin if a[minInd]>a[i] then minInd:=i; end; result:=minInd; end; function MyMax(a: array of real): integer; begin var maxInd:=0; for var i:=1 to a.Length-1 do begin if a[maxInd]<=a[i] then maxInd:=i; end; result:=maxInd; end; begin //использование методов var n:=readinteger; var a:=readArrreal(n); var t:=System.DateTime.Now; var minInd:=a.IndexMin; var maxInd:=a.LastIndexMax; var srez1:=a[minind+1:maxind].sum; println('Результат 1: ',srez1); var t1:=System.DateTime.Now; println('Время выполнения: ',t1-t); // без использования методов t:=System.DateTime.Now; minind:= MyMin(a); maxind:= MyMax(a); srez1:=a[minind+1:maxind].sum; println('Результат 2: ',srez1); t1:=System.DateTime.Now; println('Время выполнения: ',t1-t); end. |
sort
). Как и для предыдущей задачи, сделайте хотя бы 2 варианта работы и сравните их. Фрагмент кода:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | procedure MySort(c: array of integer); begin // сортировка методом Пузырька for ... for ... ... end; begin var a:=arr(1,3,5,6,12); var b:=arr(2,6,8,12,16); var c:=a+b; //использование методов var t:=System.DateTime.Now; ... ... var t1:=System.DateTime.Now; println('Время выполнения с методом: ',t1-t); t:=System.DateTime.Now; //без использования методов ... ... ... end. |