Студопедия
Случайная страница | ТОМ-1 | ТОМ-2 | ТОМ-3
АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатика
ИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханика
ОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторика
СоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансы
ХимияЧерчениеЭкологияЭкономикаЭлектроника

Связанные динамические списки

Читайте также:
  1. a) Магнитосвязанные линейные индуктивности.
  2. А) Аэродинамические характеристики здания
  3. В. Болезни, связанные с групповыми состояниями
  4. Взаимосвязанные сценарии
  5. Вредные стороны совокупления, связанные с этим состоянием, и злокачественность некоторых его способов
  6. Г. Проблемы мистиков, связанные с нынешними лучевыми влияниями
  7. Глава 6. СПИСКИ УЧАСТНИКОВ РЕФЕРЕНДУМА

Способ.

Procedure new (p);
где р -параметр типа указатель.

После выполнения этой процедуры переменная р получит значение первой свободной ячейки из «кучи», в которой может разместиться данное того типа, который задан в описании указателя р.

Пример:

Var A, B:^ integer;

C:^ real;

Begin new(A);

New(C);

В первый момент «куча» свободна и переменная heapptr имеет то же значение, что и heaporg (указатель начала «кучи»), т.е. указывает на начало «кучи».

После выполнения процедуры new(А) переменная А получит значение heapptr и по этому адресу будет выделено 2 байта памяти, т.к. А – указатель на тип integer. Таким образом, heapptr увеличивает значение на 2. В результате выполнения процедуры new(C) переменная С получит значение heapptr. И heapptr увеличит свое значение на 6, т.к. С – указатель на тип real. В итоге heapptr увеличит значение на 8.

Способ.

Значение указателя можно изменить с помощью оператора присваивания

<указатель 1>: =<указатель 2>;

при этом необходимо, чтобы оба указателя были одного и того же типа. Действие такого оператора приводит к тому, что <указатель 1> будет указывать на ту же ячейку в «куче», что и <указатель 2>, т.е. будет иметь значением тот же адрес.

Можно написать: А: = В;

В частности, любому указателю можно присвоить стандартное значение пустого адреса: А: = Nil; В результате этого А не будет указывать ни на одну ячейку.

Способ.

Присвоить значение переменной - указателю можно использовав процедуру Getmem(p, size); где р – переменная-указатель, а size – переменная целого типа. Эта процедура позволяет выделить в куче область необходимых размеров size и присвоить адрес этой области переменной р.

Способ.

Переменной типа указатель можно присвоить значение с помощью оператора задания адреса:

Y: = @ x;

где у – переменная типа указатель, а х – простая переменная. В результате у получает значение адреса ячейки памяти, в которой хранится х.

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

Пример: Пусть указатель у указывает на х (у: = @ x;), тогда в результате выполнения оператора y ^: = 5; значение переменной х будет равно 5, т.е. у^ - это значение, на которое указывает указатель у.

 

Динамические переменные

 

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

Выделение памяти для динамической переменной осуществляется вызовом процедуры new. После того, как указатель приобрел некоторое конкретное значение, отличное от nil, т.е. стал указывать на конкретный адрес «кучи», по этому адресу может быть размещено значение соответствующего типа.

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

<имя указателя>^

Пример: подсчитаем сумму двух динамических переменных.

Program dinam_peremennie;

Var p1, p2, p3:^integer;

Begin new (p1); {создаются переменные типа integer и их адреса

new (p2); присваиваются указателям p1, p2, p3 }

New (p3);

p1^:=10;

p2^:=p1^+1;

p3^:=p1^+p2^;

writeln (‘сумма чисел p1^ и p2^=', p3^);

Readln;

End.

Таким образом, значение, на которое указывает указатель, обозначается с помощью крышки ^, поставленной после имени указателя.

Если за именем указателя нет ^, то это адрес ячейки памяти, если же есть ^, то это значение, которое расположено по данному адресу.

р1^ - значение, на которое указывает указатель р1.

р1 – указатель (адрес ячейки, где расположено число).

Отметим, что нельзя смешивать указатели и данные в одно выражение:

p1:= sqr(p1^); – так делать нельзя!!!

После того, как динамическая переменная стала не нужна, ее можно уничтожить, а освободившиеся ячейки вернуть в «кучу», для этого используется процедура dispose(p); где р – переменная-указатель. После выполнения этой процедуры ячейки, содержащие значение p^ будут считаться свободными, но при этом значение p^ не изменится. Следовательно, использование p^ может привести к порче других динамических переменных, поэтому рекомендуется сразу после обращения к процедуре dispose указателю присвоить: p:= Nil; Процедура dispose(p) предназначена для освобождения указателя, который раньше получил свое значение с помощью процедуры new(p).

В том случае, если указатель имеет тип pointer и получил значение с помощью процедуры Getmem (p, size), тогда для его освобождения используется процедура Freemem (p, size).

Динамические структуры данных

 

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

1. Очередь организована по принципу FIFO (First Input First Output – первым вошел и первым вышел). Схематически можно представлять это в виде трубочки с одним входом и с одним выходом:

 

 
 


 

2. Стек организован по принципу LIFO (Last Input First Output - последним вошел, первым вышел). Схематически это можно изобразить в виде трубочки с запаянным концом.

 

 

 
 

 

 


3. Список является обобщением очереди и стека. В списке возможен доступ к любому элементу, он допускает вставку любого элемента в любое место. А также исключение элемента из любого места списка.

Если мы попытаемся использовать статические переменные структурных типов (массивы, записи, множества) для организации перечисленных динамических структур, то мы столкнемся с большими трудностями:

1) при описании переменных структурного типа необходимо заранее указать число их компонентов, а в данном случае оно неизвестно;

2) компоненты статических переменных структурных типов располагаются в памяти в подряд расположенных ячейках. Поэтому добавление элемента в такую структуру или удаление элемента из нее связано с перемещением всех остальных элементов статической структуры на новое место в памяти. Это требует больших затрат машинного времени.

При использовании динамической памяти эти проблемы устраняются, поскольку:

1) отсутствует описание динамических элементов;

2) элементы динамических структур размещаются в памяти в виде цепочки связанных структур. Такое размещение в памяти предполагает, что каждый элемент может быть помещен в любое свободное место, но при этом в каждом элементе есть указатель на следующий или предыдущий элемент связанной структуры.

 


Связанные динамические списки

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

 

 

Таким образом, каждый элемент списка представляет собой запись, состоящую из 2-х частей:

§ информационная часть;

§ часть, обеспечивающая связь cо следующим (возможно с предыдущим элементом списка). Список, в котором обеспечивается связь только со следующим элементом, называется односвязанным.

 

 

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

 

Type p_stud=^Student;

{^ Student – тип указателя, который обеспечивает связь между
элементами списка}

Student = record {запись Student описывает тип элемента списка}

Fam: string[20 ];

Name: string[15]; { информационная часть элемента}

Grup: integer;

Adress: string[60];

Next: p_stud; {указатель на следующий элемент списка }

End;

Var head: p_stud; {указатель на первый элемент списка }

Тип Student необходим для описания типа указателя p_stud. Указатель невозможно описать без раздела type, в то же время тип p_stud нужен для описания поля Next в записи Student. Таким образом, идентификатор Student используется до его описания, этим нарушается одно из требований языка Pascal, Это исключение сделано только для описания указателей, чтобы сделать возможным создание связанных структур.

Добавлять данные можно в начало, в конец, в нужное место списка.

Во всех этих случаях необходимо корректировать указатели.

Изобразим схематически процесс добавления элементов в начало односвязанного списка.

1. Список пустой, указатель head ни на что не указывает (nil).

head

 
 


· т

 

2. После добавления первого элемента head указывает на этот элемент.

head

 
 

 

 


3.После добавления второго элемента в начало списка head указывает на этот новый элемент (curr – указатель на текущий элемент).

 

Head

 
 

 


 
 

 

 


Рассмотрим пример программы, которая формирует список студентов, добавляя фамилии в начало этого списка. Данные для списка вводятся с клавиатуры. Если вместо ввода очередной фамилии нажата сразу Enter (это равносильно вводу пустой строки, длина которой равна 0), тогда программа начнет распечатывать введенный нами список.

 


Дата добавления: 2015-12-08; просмотров: 87 | Нарушение авторских прав



mybiblioteka.su - 2015-2024 год. (0.014 сек.)