- •Технология программирования (pascal)
- •V. Структуры и организация данных
- •2. Динамические структуры данных
- •2.2. Указатели и их использование для работы с динамическими переменными.
- •1. Проверка наличия требуемого объема памяти в heap-области.
- •2.3. Динамический массив.
- •2.4. Линейные связанные структуры.
- •2.5. Линейные списки.
- •1. Объявление (описание) данных односвязного списка:
- •2. Создание первого элемента списка и заполнение полей:
- •3. Создание следующего элемента и связывание его с первым элементом:
- •4. Создание списка из n элементов:
- •5. Удаление элемента списка:
- •1. Объявление данных двусвязного списка:
- •2. Пример программы работы с двусвязным списком.
2. Создание первого элемента списка и заполнение полей:
new(current);
current^.data:= ’данные в первом элементе списка ’;
current^.next:=nil;
Поле current^.next является указателем, доступ к его содержимому осуществляется через указатель current.
3. Создание следующего элемента и связывание его с первым элементом:
head:=current;
new(last);
last^.data:= ’данные во втором элементе списка ’;
last^.next:=nil;
current^.next:=last;
Перед созданием следующего элемента указателю head присваивается значение указателя current для того, чтобы сохранить адрес начала линейного списка (указатель на первый элемент списка является заголовком). Если этого не сделать, то когда значение указателя current будет переопределено, то потеряется возможность доступа к данным, хранящимся в первом элементе списка.
4. Создание списка из n элементов:
head:= nil;
for i:=1 to n do
begin
new(current);
readln(current^.data);
current^.next:=nil;
if head=nil then
head:=current
else
last^.next:= current;
last:= current;
end;
5. Удаление элемента списка:
Удаление элемента из списка заключается, в первую очередь, в переопределении указателей, связанных с данным элементом (указывающих на него), но удаленный элемент данных при этом продолжает занимать память, хотя доступ к нему будет потерян. Для корректной работы с динамическими структурами следует освобождать память при удалении элемента структуры:
dispose(current);
Линейный двусвязный (двунаправленный) список
Односвязный список неудобен тем, что при попытке вставить некоторый элемент перед текущим элементом требуется обойти список, начиная с заголовка, чтобы изменить значение указателя в предыдущем элементе списка. Чтобы устранить данный недостаток, вводится второй указатель в каждом элементе списка: первый указатель связывает данный элемент со следующим элементом, а второй – с предыдущим. Такая динамическая структура данных называется линейным двусвязным (двунаправленным) списком.
Важным свойством линейного двусвязного списка является то, что для доступа к его элементам не обязательно хранить указатель на первый элемент, а достаточно иметь указатель на любой элемент списка, поскольку первый элемент всегда можно найти по цепочке указателей на предыдущие элементы, а последний – по цепочке указателей на следующие.
1. Объявление данных двусвязного списка:
type
listPtr = ^list;
list = record
number, data: integer;
next, prev: listPtr;
end;
В данном случае number – поле для хранения порядкового номера элемента, data – поле для хранения данных элемента, prev и next – указатели на предыдущий и последующий элемент соответственно.
2. Пример программы работы с двусвязным списком.
Программа выполняет следующие операции с элементами списка:
-
добавление элемента в начало списка и вставка элемента после текущего;
-
удаление текущего элемента;
-
вывод списка.
В данном примере используется список с заголовочным элементом, т. е. специальным нулевым элементом, который не содержит данных. Такая организация списка используется для того, чтобы операции удаления и добавления элементов в начало списка производились так же, как в середину или в конец списка.
Одна из возможных реализаций программы с использованием модульного программирования
Program mod_list; { основная программа }
uses menu_proc;
begin
menu_work;
end.
Unit types; { модуль описания типов }
Interface { интерфейсная часть }
type
point=^element;
element=record
data:string[10];
last, next:point;
end;
Implementation { часть реализации в данном модуле пустая }
{ часть инициализации в данном модуле отсутствуют }
end.
Unit work_proc; { модуль процедур обработки линейного двусвязного списка }
Interface { интерфейсная часть }
uses types;
var
head: point;
pnt, pcur, p: point;
procedure current_elem(head: point, var pcur:point); { назначение элемента текущим }
procedure output_list(head:point); { вывод списка элементов }
procedure add_ins(var pcur:point); { добавление или вставка элемента после текущего }
procedure del_elem(head,pcur:point); { удаление текущего элемента }
procedure del_list(var head:point); { удаление списка }
Implementation { часть реализации }
procedure current_elem; { назначение текущего элемента }
var
s: string[10];
pr: boolean;
begin
readln(s);
p:=head;
pr:=false;
repeat
if p^.data=s then
begin
pcur:=p;
pr:=true;
end
else
p:=p^.next;
until (pr) or (p=nil);
end;
procedure output_list; { вывод списка элементов }
var
i: integer;
begin
p:=head;
i:=0;
repeat
if i=0 then
writeln('head')
else
writeln('(',i,') ',p^.data);
p:=p^.next;
i:=i+1;
until p=nil;
end;
procedure add_ins; { добавление или вставка элемента в список после назначенного текущего элемента }
begin
new(p);
readln(p^.data);
p^.last:=pcur;
p^.next:=pcur^.next;
pcur^.next:=p;
pnt:=p^.next;
if pnt<>nil then
pnt^.last:=p;
end;
procedure del_elem1(head:point, var pcur:point, var ppr: boolean); { вложенная процедура процедуры del_elem удаления текущего элемента }
begin
p:=head;
while (p^.next<>pcur) and (p^.next<>nil) do
p:=p^.next;
if p^.next=nil then
begin
pcur:=head;
ppr:=true;
end
else
begin
p^.next:=pcur^.next;
dispose(pcur);
if p^.next<>nil then
p^.next^.last:=p;
end;
end;
procedure del_elem; { удаление текущего элемента }
var
pr: boolean;
begin
if (pcur=head) and (head^.next=nil) then
begin
writeln('List is empty');
readln;
end
else
begin
pr:=false;
del_elem1(head,pcur,pr);
if pr then
begin
writeln('There is no such element of the list');
readln;
end;
end;
end;
procedure del_list; { удаление списка }
begin
repeat
p:=head;
head:=head^.next;
dispose(p);
until head=nil;
end;
{ часть инициализации в данном модуле отсутствует }
end.
Unit menu_proc; { модуль формирования меню }
Interface
uses crt, types, work_proc;
var
n: byte;
procedure menu_work;
Implementation
procedure menu_work;
begin
new(pcur);
head:=pcur;
pcur^.next:=nil;
pcur^.last:=nil;
repeat
clrscr;
writeln('1 - set current element');
writeln('2 - output list');
writeln('3 - add or insert element after current one');
writeln('4 - delete current element');
writeln('0 - exit');
readln(n);
clrscr;
case n of
1: begin
writeln('set current element: ');
current_elem(head,pcur);
end;
2: begin
output_list(head);
readln;
end;
3: begin
writeln('input element:');
add_ins(pcur);
end;
4: del_elem(head,pcur);
end;
until n=0;
del_list(head);
end;
end.