Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции Алгоритмизация.doc
Скачиваний:
2
Добавлен:
01.04.2025
Размер:
445.44 Кб
Скачать

Тема 11. Динамические структуры данных. Указатели. Работа с очередями и сте­ком. (2 часа)

План лекции 13:

  1. Ссылочный тип

  2. Статические, динамические переменные

На языке Паскаль, программист может решать вопросы динамического распределения памяти, используя ссылочный тип данных.

Ссылочный тип определяется в следующем виде:

type

<имя ссылочного типа>=^<имя базового типа>;

Примеры:

type

mas=array[1..10] of integer;

Ptr= ^integer;

link = ^mas;

linkchar = ^char;

tie = ^real;

Описание переменных ссылочного типа:

var

p:ptr;

v:link;

a:^real;

Значение ссылочного типа (неформально) – адрес в памяти, где располагается конкретное значение базового типа. Есть специальный указатель, который «никуда не указывает». В адресном пространстве оперативной памяти выделяется один адрес, в котором заведомо не может быть размещена никакая переменная. На это место в памяти и ссылается такой пустой или «нулевой» указатель, который обозначается служебным словом nil.

Указатель nil считается константой, принадлежащей любому ссылочному типу. Иными словами, это значение можно присваивать любому указательному типу.

  • Сравнение на равенство (=), сравнение на неравенство (<>)

– ссылаются ли два указателя на одно и то же место в памяти?

Примеры: var p1,p2:ptr;

......

sign:=p1=p2;

if p1<>nil then ....

Для того чтобы по указателю на переменную получить доступ к самой этой переменной, необходимо после переменной-указателя поставить знак '^'; p1^ есть «переменная», на которую ссылается p1. Такая конструкция может находиться в любом контексте, в котором допустимо нахождение самой указываемой переменной. Если p1 имеет тип ^integer, то p1^ имеет тип integer.

Разыменование некорректно, если ссылочная переменная имеет значение nil.

Поэтому p1:=nil;

p1^:=2;

некорректно и приводит к трудно распознаваемым ошибкам.

Пример: var p1,p2:^integer;

Пусть переменные p1^ и p2^ уже имеют значения 1 и 2 соответственно (как это сделать  смотрите ниже). Тогда различные результаты следующих присваиваний изображены на рис. 1.

p1:=p2;

p1^:=p2^;

Исходное состояние:

После присваивания p1:=p2

После присваивания p1^:=p2^

Рис.1 Различия в присваиваниях

Динамические переменные – это те, которые образуются и уничтожаются в произвольный момент выполнения программы.

Средство доступа к статическим переменным есть идентификатор. Динамические переменные, количество которых и место расположения в памяти неизвестны, невозможно обозначить идентификаторами. Средство доступа к динамическим переменным – указатель на место их текущего расположения в памяти.

Процедура new(<переменная ссылочного типа>) предназначена для создания динамической переменной:

  • в динамической области памяти отводится место для хранения переменной, тип которой совпадает с базовым типом указателя-переменной;

  • переменной, переданной в параметре, присваивается указатель на отведенную область памяти.

Пример: type

mas=array[1..10] of integer; link=^mas;

var t:link;

........

new(t);

Отводится память, достаточная для хранения массива типа mas. Переменной t присваивается адрес этой памяти. Теперь возможен доступ к элементам массива, например:

t^[i]:=0;

t^[i]:=t^[j];

Переменная t является статической, место в памяти для ее значения выделено при трансляции. Переменная t^ – динамическая, она появляется только при выполнении процедуры new(t).

Процедура dispose(<переменная ссылочного типа>) служит для освобождения памяти, отведенной с помощью процедуры new с той же переменной.

Рис. 2 иллюстрирует применение процедур new и dispose (переменные p1 и p2 имеют тип ^integer):

new(p1);new(p2);

p1^:=1; p2^:=2;

p1:=p2;

dispose(p2);

Рис. 2  Результат выполнения фрагмента

План лекции 14:

  1. Линейный список

  2. Циклически связанный список

Создание и обработку структур данных, компоненты которых связаны явными ссылками. Особое значение придается структурам простой формы; приемы работы с более сложными структурами можно получить из способов работы с основными видами структур: линейными списками и деревьями.

Самый простой способ соединить, или связать, множество элементов – это расположить их линейно в списке. В этом случае каждый элемент содержит только одну ссылку, связывающую его со следующим элементом списка. Пусть тип link описан следующим образом:

type

link = ^node;

node = record

info:string;

next:link

end;

var s,p:link;

Мы можем создать с помощью этого типа список, изображенный на рис. 5:

Рис. 1  Список элементов типа link

Переменная – ссылка s  указывает на первую компоненту списка. По-видимому, самое простое действие, которое можно выполнить со списком, показанным на рисунке 1, это вставить в его начало некоторый элемент (рис. 2).

new(p);

p^.info:='Петров';

p^.next:=s;

s:=p;

Рис. 2  Вставить элемент в начало списка

Операция включения элемента в начало списка определяет, как можно построить список: начиная с пустого списка, последовательно добавляя элементы в его начало.

Пусть число связываемых элементов равно n. Тогда формировать список можно следующим образом:

s:=nil; {начали с пустого списка}

while n>0 do

begin

new(p); p^.next:=s;

read(p^.info);

s:=p;n:=n-1 end;