
Пример 2.
P
rogram
ex2;
Var i:integer; p,q:^integer; {рис.1а}
Begin
New(p); new(q); i:=5; {рис.1б}
P^:=7; q^:=p^-i; i:=i+1; {рис.1в}
P^:=q^+i; q:=p; write(q^); {рис 1г}
End.
Место в памяти, ссылка на которое прежде являлась значением переменной q, теперь стало недоступным: нельзя, например, воспользоваться записанным там значением, нельзя освободить это место с помощью dispose, поскольку на него нет ссылки. Это место в памяти представляет так называемый «мусор». От него следовало бы избавиться до изменения значения переменной q. Заменим три последних оператора в программе ех2 на следующую группу операторов: P^:=q^+i; dispose(q);q:=p; write(q^); {рис 2a}
Предостережение. Если в ситуации, изображенной на рис.2а, выполнить dispose(p), то место в памяти, ссылка на которое была значением переменных p и q, освободится. После этого не только значение переменной р, но и значение переменной q будет неопределенным.
Стандартные процедуры new и dispose позволяют динамически порождать программные объекты и уничтожать их, что дает возможность использовать память компьютера более эффективно.
Пример 3.
Составить программу, которая в вещественном массиве с 1500 элементами находит элемент, номер которого равен наибольшему значению массива, состоящему из 3000 целых чисел.
Алгоритм решения.
организуем динамический массив из целых чисел [1..3000]
найдем в нем наибольший элемент к
освободим память от этого массива и создадим динамический массив действительных чисел
найдем элемент в этом массиве, номер которого равен к.
program ex3;
uses crt;
type ra=array[1..1500]of real;
ia=array[1..3000] of integer;
var k,i:integer;
p:^ra;q:^ia;
Begin
clrscr; randomize; k:=0;
new(q);
for i:=1 to 30 do
begin
q^[i]:=random(15)+6; write(q^[i]:4);
if q^[i]>k then k:=q^[i];
end;
writeln; writeln;
writeln('k= ',k);dispose(q);
new(p);
for i:=1 to 30 do
begin
p^[i]:=random(15)+random; write(p^[i]:5:1);
end;
writeln; writeln;
writeln('iskom element = ', p^[k]:4:1);
readkey;
End.
Однонаправленные списки и операции над ними
Главная возможность, которую предоставляет наличие ссылочных типов и ссылочных переменных в Паскале, - это возможность построения с их помощью объектов со сложной, меняющейся структурой, простейшим из которых является однонаправленный список.
Структура «однонаправленный список» строится подобно очереди на прием к врачу: клиенты сидят на любых свободных местах, но каждый из них знает, за кем он стоит (т.е. данные размещаются на свободных местах в памяти, но каждый элемент содержит ссылку на предыдущий или следующий элемент).
Однонаправленный список – это цепочка звеньев данных, где вместе с элементами указывается адрес следующего (или предыдущего) элемента.
Каждое звено списка обычно является записью, состоящей из двух частей:
информационная часть (одно или несколько полей). Если р - ссылка на звено, то p^.имя поля1, p^.имя поля2, … - имена полей такого звена.
Ссылочная часть содержит ссылку на следующее (или предыдущее) звено списка.
Описание списка.
При описании списка возникает проблема, что раньше описывать: звено, представляющее запись и содержащее поле-ссылку, или ссылку на звено? В Паскале принято сначала описывать ссылку на звено, например:
Type te=тип инф.части;
Ss=^zveno; {ссылка на звено}
Zveno=record {звено}
Inf: te; {информационная часть}
Sled:ss {ссылочная часть}
End;
Var p,u:ss;
Основные операции со списком.
1. Формирование списка
2. Вывод содержимого (просмотр элементов) списка на экран
Удаление звена из списка
Включение звена в список
Поиск элемента в списке
Чтобы оперировать с элементами списка единообразно и просто, полезно ввести в употребление заглавное звено список. Информационную часть заглавного звена можно не использовать или использовать для побочных целей, например, для хранения величины – количества звеньев списка. Ссылочная часть заглавного звена содержит ссылку на первое звено списка, таким образом, у каждого звена списка будет “предыдущее” звено.
Пример 4. Процедура формирования списка натуральных чисел вводимых с клавиатуры.
Ввод числа 0 означает окончание формирования списка. Пусть u и p – имена ссылок на заглавный и текущий звенья списка.
Алгоритм:
Сначала выделяем место в памяти для заглавного звена New(u), текущая ссылка - р вначале указывает на заглавное звено;
Далее, если вводится число неравное нулю, то с помощью ссылки p^.sled формируется очередное звено списка, и текущий указатель р переводится на это звено
Procedure form;
var s:integer;
Begin
New(u); p:=u; u^.sled:=nil; Writeln(‘введите список натуральных чисел, окончание ввода - 0’);
Readln(s);
While s<>0 do
begin new (p^.sled);p:=p^.sled; p^.inf:=s; p^.sled:=nil;
readln(s);
end; writeln
End;
Пример 5. Процедура вывода элементов списка на экран
Алгоритм:
Текущую ссылку р связываем с первым звеном списка (u^.sled -имя указателя на первое звено);
Затем связываемся со вторым звеном, изменив значение р на значение p^.sled, и продолжаем цикл просмотра элементов списка, пока выполняется условие p<>nil. Если список был пустым (было выполнено отношение p=nil), то тело цикла не выполнится ни разу и не будет выведено ни одного числа.
Procedure print;
Var p:ss;
Begin p:=u^.sled;
While p<>nil do
begin write (p^.inf, ‘ ‘);
P:=p^.sled;
end; writeln;
End;
Пример 6. Процедура удаления звена из списка
Напишем процедуру, удаляющею звено из списка с помощью ссылки р на звено, за которым следует удаляемое звено.
Операция удаления звена из списка требует изменения лишь одной ссылки, что геометрически выглядит как изменение одной стрелки:
Список до удаления звена с элементом с