
Программирование в среде Delphi
Динамические структуры данных
Организация связных списков
Очередь
Динамическая память и указатели уже рассматривались в параграфе 1.5 первой части данного учебного пособия «Создание консольных приложений». Эти знания мы будем использовать при изучении организации связных списков.
Связный список – это динамическая структура, в которой отдельные элементы, имеющие тип запись, последовательно связаны друг с другом посредством того, что одно из полей каждого элемента связного списка имеет тип указатель и содержит адрес очередного элемента списка.
Однонаправленный связный список схематически можно представить в виде
первый
элемент
списка
указатель
второй
элемент
списка
указатель
. . .
последний
элемент
списка
указатель
nil
Опишем динамическую структуру данных, которая является однонаправленным списком. Каждый элемент этой динамической структуры – это запись, имеющая два поля. Первое поле отводится под целое число (информационное поле), а второе содержит адрес следующего элемента списка.
type link = ^elem;
elem = record
val : integer;
next : link
end;
var L : link;
Переменная L предназначена для указателя на элемент списка. Тогда L^ – это сам элемент списка (динамическая переменная типа запись). Таким образом, L^.val и L^.next – это, соответственно, обозначения для полей этой записи. В Delphi знак разыменования ( ^ ) при обращении к полям динамических структур можно опускать, т.е. к полям данной динамической структуры можно обратиться следующим образом: L.val и L.next
Построим список, информационные поля которого будут содержать целые числа, прочитанные из текстового файла file1.txt.
type link = ^elem;
elem = record
Val : integer;
next : link
end;
Var l, p, q : link;
begin
assignfile(f, ' file1.txt ');
reset(f);
new(L); {L – указатель на первый элемент списка}
read(f, L.val); {В информационное поле первого элемента записали первое число}
p:=L; {p – указатель на последний созданный элемент списка}
while not eof(f) do
begin
new(q) {q – указатель на очередной элемент списка}
read(f, q.val); {заполнили его информационное поле}
p.next:=q; {записали в ссылочное поле предыдущего элемента адрес q}
p:=q {объявили элемент q последним}
end;
p.next:=nil; {в ссылочное поле последнего элемента записали адрес nil}
closefile(f)
end.
Построенный список называется очередью. Вновь созданные элементы пристраиваются в конец очереди. Работа с элементами очереди начинается с её начала. Для очереди используется обозначение fifo (first in first out – первым пришёл, первым ушёл).
Задача 1. Создать очередь, информационные поля которой содержат числа из текстового файла file1.txt. Вывести значения информационных полей очереди в поле метки. Содержимое файла file1.txt:
14 -9 8 -22 39
-1 -13 0 4 -7
27 5 -2 18 3
Окно работающего приложения:
На форму поместим кнопку button1 с надписью «Создать очередь» и кнопку button2 с надписью «Показать очередь». Для метки Label1 установим свойства
-
AutoSize
False
WordWrap
True
Width
230
Height
60
Полный текст модуля:
unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
end;
type link = ^elem;
elem = record
Val : integer;
next : link
end;
var Form1: TForm1; L:link;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var p, q : link; f : textfile;
begin
assignfile(f, ' file1.txt '); reset(f);
new(L);
read(f, L.val);
p:=L;
while not eof(f) do
begin
new(q); read(f, q.val); p.next:=q; p:=q
end;
p.next:=nil;
closefile(f); showmessage(' Очередь создана ')
end;
procedure TForm1.Button2Click(Sender: TObject);
var p:link;
begin
label1.Caption:='';
p:=L;
while p<>nil do
begin
label1.Caption:=label1.Caption + inttostr(p.val) + ' '; p:=p.next
end;
end;
end.
Задача 2. Создать очередь, информационные поля которой содержат числа из текстового файла file1.txt. Вставить в список новый элемент с информационным полем d после первого элемента. Содержимое файла file1.txt: 14 -9 8 -22 39
-1 -13 0 4 -7
27 5 -2 18 3
Проект для решения задачи 2 будем создавать на основе проекта задачи 1. Добавим на форму приложения задачи 1 кнопку button3 с надписью «Вставка после 1 элемента». Со страницы Additional добавим компонент LabeledEdit1, представляющий собой комбинацию однострочного текстового поля с меткой. Надпись в метке определяет свойство EditLabel (Caption). В модуль Unit1 добавим процедуру обработки события щелчка по кнопке «Вставка после 1 элемента».
procedure TForm1.Button3Click(Sender: TObject);
var r:link; d:integer;
begin
d:=strtoint(LabeledEdit1.Text);
new(r); r.val:=d; r.next:=L.next; L.next:=r;
end;
Вставку элемента, осуществляемую этой процедурой, схематически можно изобразить следующим образом: