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

2

«УТВЕРЖДАЮ»

Ректор университета

_________________А.В. Лагерев

«________»_____________2006г.

Алгоритмические языки и программирование Работа с динамическими структурами

Методические указания к выполнению лабораторной работы №14

для студентов дневной формы обучения

специальностей 075300 – "Организация и технология

защиты информации",

220300 – "Системы автоматизированного проектирования"

Брянск 2006

УДК 004.43

Алгоритмические языки и программирование. Работа с динамическими структурами: методические указания к выполнению лабораторной работы №14 для студентов дневной формы обучения специальностей 075300 – "Организация и технология защиты информации", 220300 – "Системы автоматизированного проектирования".– Брянск: БГТУ, 2006. - 12 с.

Разработал: Ю.А. Леонов, асс.

Научный редактор Ю.М. Казаков

Редактор издательства Л.И. Афонина

Компьютерный набор Ю.А. Леонов

Рекомендовано кафедрой «Компьютерные технологии и системы» БГТУ (протокол № от )

Темплан 2006г., п.

Подписано в печать Формат 60х84 1/16. Бумага офсетная. Офсетная печать.

Усл. печ. л. 1,45 Уч. – изд. л. 1,45 Тираж 50 экз. Заказ Бесплатно

Брянский государственный технический университет.

Брянск, бульвар 50-летия Октября, 7, тел. 55-90-49.

Лаборатория оперативной полиграфии БГТУ, ул. Институтская, 16

  1. Цель работы

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

Продолжительность работы – 6ч.00мин.

  1. Теоретическая часть

2.1. Классификация динамических структур данных

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

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

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

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

Кольцевые списки – это такие же данные, как и линейные списки, но имеющие дополнительную связь между последним и первым элементами списка.

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

Стек – частный случай линейного односвязного списка, для которого разрешено добавлять или удалять элементы только с одного конца списка, который называется вершиной (головой) стека.

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

Деревья – это динамические данные иерархической структуры произвольной конфигурации. Элементы дерева называются вершинами (узлами). Вершины, из которых не выходит ни одной ветви, называют листьями.

2.2. Организация взаимосвязей в динамических структурах

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

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

На рис. 1. показаны два элемента и связь между ними. Связь между двумя элементами динамической структуры можно создать, записав адрес элемента, на который ссылается элемент, в указательное поле.

2.3. Порядок работы и основные операции с динамическими структурами

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

Рассмотрим необходимые объявления данных и операции над данными на примере динамической структуры представленной на рис. 1.

  1. Объявление типов данных элементов динамической структуры.

  2. Выделение памяти под переменные указатели.

  3. Выделение памяти под элементы динамической структуры.

  4. Занесение информации.

  5. Организация связей.

  6. Удаление элементов.

Объявление типов данных элементов динамической структуры

Для создания динамической структуры необходимо описать тип элемента и тип, указывающий на элемент. Так как в элементе динамической структуры присутствуют поля разных типов данных, то необходимо воспользоваться типом данных record, который позволяет объединить разные типы данных в один тип.

Type

TPtr = ^TElem;

TElem = record

Inf: Integer;

Link: TPtr;

End;

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

Выделение памяти под переменные указатели

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

Память под указатели выделяется путем описания переменных указателей в разделе описание переменных.

Var Elem1, Elem2: TPtr;

Выделение памяти под элементы динамической структуры

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

New(Elem1);

New(Elem2);

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

Занесение информации

При добавлении элемента в динамическую структуру передают информационную часть. В нашем примере мы просто инициализируем информационные поля абстрактными значениями.

Elem1^.Info:=3.5;

Elem2^.Info:=10;

Для того чтобы инициализировать информационное поле необходимо обратится к переменной указатель, далее делаем операцию разыменования ^, которая дает возможность, обратится к данным по соответствующему адресу. После операции разыменования мы получаем доступ к структуре TElem (тип record). Используя инструмент обращения к полям типа запись мы получаем доступ к информационному полю.

Организация связей

Свяжем два элемента динамической структуры представленной на рис. 1. Для этого необходимо в поле связи элемента Elem1 записать адрес элемента Elem2.

Elem1^.Link:=Elem2;

Также на рис. 1 в поле Link второго элемента показан конец списка. Для указания конца списка нужно в указательное поле последнего элемента занести значение nil.

Elem2^.Link:=nil;

Удаление элементов

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

Dispose(Elem1);

Dispose(Elem2);

Рассмотрим подробнее организацию структуры линейный односвязный список.

2.4. Работа с динамической структурой «линейный двусвязный список»

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

Каждый элемент списка содержит поле данных info (оно может иметь сложную структуру) и указательные поля на предыдущий элемент (prev) и следующий элемент (next). Указательные поля первого элемента списка на предыдущий элемент (prev) и последнего элемента списка на следующий элемент (next) должны содержать пустой указатель (nil).

Определим тип данных элемента списка, а также указательный тип данных на элемент списка.

Type

TPtr=^TElem;

TElem=record

next: TPtr; {указатель на предыдущий элемент}

info: integer; {информационное поле}

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

end;

Добавление элемента в список

Добавление элемента будем производить только в конец списка.

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

Представим процедуру добавления элемента в список.

Procedure AddElem(_info: integer);

Var P: TPtr;

Begin

New(P); {выделяем память под «новый» элемент}

if Top=nil then {случай, когда в списке нет элементов}

begin

P^.prev:=nil;

Top:=P;

end else begin {случай, когда в списке есть элементы}

Last^.next:=P;

P^.prev:=Last;

end;

{общая часть для обоих случаев}

P^.info:=_info;

P^.next:=nil;

Last:=P;

End;

Замечание: в представленной процедуре добавления элемента в список не была предусмотрена проверка наличия свободной динамической памяти для добавления элемента.

Удаление элемента из списка

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

Функция нахождения элемента выглядит следующим образом:

Function FindElem(_num: integer; _StartElem: TPtr): TPtr;

Var i: integer;

Begin

if (num<1) then begin FindElem:=nil; exit; end;

for i:=1 to _num-1 do

begin

if (_StartElem^.next=nil) then begin FindElem:=nil; exit; end;

_StartElem:=_StartElem^.next;

end;

FindElem:=_StartElem;

End;

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

На рис. 3 представлена схема удаления элемента из списка. Обратите внимание, что для перестройки связей необходимо инициализировать поля 1, 2, 3, 4 новыми значениями, причем доступ к ним возможен только через адрес удаляемого элемента P.

После удаления элемента P необходимо адрес элемента P^.next поместить в поле 1, адрес элемента P^.prev поместить в поле 4. При удалении элемента из списка можно выделить три различных случая, которые необходимо рассматривать отдельно: удаление первого, последнего и удаление элемента из средней части списка.

Представим код процедуры удаления элемента.

Procedure DelElem(_num: integer);

Var P: TPtr;

Begin

P:=FindElem(_num, Top); {поиск адреса удаляемого элемента}

if (P=nil) then begin Writeln('This element is not found'); exit; end;

if (P=Top) then {случай удаления первого элемента}

begin

Top:=P^.next;

Top^.prev:=nil;

end else if (P=Last) then {случай удаления последнего элемента}

begin

Last:=P^.prev;

Last^.next:=nil;

end else begin {случай удаления среднего элемента}

P^.prev^.next:=P^.next;

P^.next^.prev:=P^.prev;

end;

Dispose(P); {освобождаем память, занимаемую элементом}

End;

Удаление списка

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

  • передаем процедуре удаления списка адрес первого элемента списка;

  • запоминаем адрес текущего элемента в переменной P;

  • находим адрес следующего элемента, который будет являться текущим;

  • освобождаем память, занимаемую элементом P;

  • процесс удаления ведем до тех пор, пока адрес следующего элемента не будет равным nil;

  • удаляем последний элемент.

Представим код процедуры удаления списка.

Procedure EraseSpisok(_StartElem: TPtr);

Var P: TPtr;

Begin

While (_StartElem^.next<>nil) Do

Begin

P:=_StartElem;

_StartElem:=_StartElem^.next;

Dispose(P);

End;

Dispose(_StartElem); {Удаляем последний элемент}

End;

Вывод списка на экран

Для вывода списка на экран воспользуемся представленным ранее алгоритмом перемещения по списку (см. алгоритм удаления списка).

Представим код процедуры вывода списка на экран.

Procedure PrintSpisok(_StartElem: TPtr);

Var P: TPtr;

Begin

While (_StartElem^.next<>nil) Do

Begin

Write(_StartElem^.info, '<->'); {вывод текущего элемента списка}

_StartElem:=_StartElem^.next;

End;

Writeln(_StartElem^.info); {вывод последнего элемента списка}

End;

Примечание: в начале работы со списком необходимо установить начальные значения глобальным переменным Top (начало списка) и Last (конец списка) равные nil; в конце работы всю выделенную динамически память необходимо освободить.