unit LinkList;
//******************************************************************************
// Данный модуль содержит объект для работы со связным списком (очередью)
// редакция 1.0.0.4
// дата последних исправлений 14/09/2006
// (c) KAN
//******************************************************************************
interface
uses KANsConverts;
//тип связный список
Type
TLinkList = ^RLinkList; // ссылка на тип элемента очереди
RLinkList = Record //тип элемента очереди
id : integer;
name: string;
next: TLinkList;
end;
TQueue = Record //указатель на начало и конец очереди
Head : TLinkList;
Tail : TLinkList;
end;
//объект для работы с двухсвязным списком
Type CTLinkList = Class
public
Constructor Create;
Destructor Destroyer;
Procedure ClearAll; //очищаем очередь
Procedure AddItem (id : integer; name : string); //добавлеяем элемент в конец очереди
Function SearchItem (id : integer) : string; //ищим элемент по id
Function SearchItemByName (name : string) : integer; //ищим элемент по имени
Function GetAllItemID: TIntArray; //возвращает спискок ID`ов
private
Count : integer; //кол-во элементов в очереди
Queue : TQueue; //начало и конец очереди
published
property ListLen: integer read Count; //кол-во элементов в очереди
property GetQueue : TQueue read Queue; // сама очередь
end;
implementation
//------------------------------------------------------------------------------
Constructor CTLinkList.Create;
//todo:добавить хэширование, при этом указывать кол-во элементов если (-1) то без хэширования...
begin
//создаём пустой связный списк - очередь
Queue.Head:=nil;
Queue.Tail:=nil;
Count:=0;
end;
//------------------------------------------------------------------------------
Procedure CTLinkList.ClearAll; //очищаем очередь
Var ListItems : TLinkList;
begin
if Queue.Head <> nil then
begin
ListItems:=Queue.Head; // смотрим список с головы
repeat
if ListItems^.next <> nil then Queue.Head:=ListItems^.next; // узнаем следующий элемент
Dispose(ListItems); // удадяем голову
ListItems:=Queue.Head;
dec(Count); // уменьшаем счетчик
until Count <= 0; //Queue.Head = nil; // повторяем пока ничего не останится
end; //if
Queue.Head:=nil;
Queue.Tail:=nil;
Count:=0;
end;
//------------------------------------------------------------------------------
Destructor CTLinkList.Destroyer;
begin
ClearAll;
end;
//------------------------------------------------------------------------------
Procedure CTLinkList.AddItem (id : integer; name : string); //добавлеяем элемент в конец очереди
Var ListItems : TLinkList;
begin
new(ListItems); //отводим памяти кусочек
ListItems^.id:=id; //заполняем все поля
ListItems^.name:=name;
ListItems^.next:=nil; //следующего элемента пока нет
if Queue.Head = nil //если очередь былла пустой,
then Queue.Head := ListItems //то новый элемент будет головой
else Queue.Tail^.next := ListItems;//иначе хвостом
inc(Count); //увеличивам счетчик кол-во элементов в очереди
Queue.Tail:= ListItems; // приписываем элемент в хвост
end;
//------------------------------------------------------------------------------
Function CTLinkList.SearchItem (id : integer) : string; //ищим элемент по id
Var ListItems : TLinkList;
Resultat : String;
NeedExit : Boolean;
begin
Resultat:=''; //в случаи чего вернем пустую строку
if Queue.Head <> nil then // проверяем очередь на пустоту
try
ListItems:=Queue.Head; // смотрим список с головы
NeedExit:=False; //снимаем признак выхода
repeat
begin
if ListItems^.id=id then //а если наши нужный id...
begin
Resultat:= ListItems^.name; // запоминаем найденый результат
NeedExit:=True; //устанавливаем признак выхода
end;
ListItems:=ListItems^.next; // узнаем следующий элемент
end;
until ((ListItems = nil) or (NeedExit)); // повторяем пока ничего не останится или нет признака выхода
finally
SearchItem := Resultat;
end; //finally
end;//Function
//------------------------------------------------------------------------------
Function CTLinkList.SearchItemByName (name : string) : integer; //ищим элемент по имени
Var ListItems : TLinkList;
Resultat : integer;
NeedExit : Boolean;
begin
Resultat:=-1; //в случаи чего вернем пустую строку
if Queue.Head <> nil then // проверяем очередь на пустоту
try
ListItems:=Queue.Head; // смотрим список с головы
NeedExit:=False; //снимаем признак выхода
repeat
begin
if ListItems^.name=name then //а если наши нужный name...
begin
Resultat:= ListItems^.id; // запоминаем найденый результат
NeedExit:=True; //устанавливаем признак выхода
end;
ListItems:=ListItems^.next; // узнаем следующий элемент
end;
until ((ListItems = nil) or (NeedExit)); // повторяем пока ничего не останится или нет признака выхода
finally
SearchItemByName := Resultat;
end; //finally
end;//Function
//------------------------------------------------------------------------------
Function CTLinkList.GetAllItemID: TIntArray; //возвращает спискок ID`ов
Var ListItems : TLinkList;
Resultat : integer;
lResultArray: TIntArray;
begin
Resultat:=0;
SetLength(lResultArray, Count);
if Queue.Head <> nil then // проверяем очередь на пустоту
try
ListItems:=Queue.Head; // смотрим список с головы
repeat
begin
lResultArray[Resultat]:= ListItems^.id; // запоминаем
inc(Resultat);
ListItems:=ListItems^.next; // узнаем следующий элемент
end;
until (ListItems = nil); // повторяем пока ничего не останится или нет признака выхода
В этом модуле Delphi реализуется связанный список данных, конкретно очередь. Модуль определяет два рекорда: RLinkList и TQueue. Тип RLinkList представляет собой отдельный элемент в очереди, который имеет три поля: id, name и next. Тип TQueue представляет собой очередь сама, с двумя полями: Head и Tail.
Модуль также определяет класс CTLinkList, который предоставляет методы для манипуляции очередью. Эти методы включают:
ClearAll: Очищает очередь, освобождая все элементы в ней.
AddItem: Добавляет элемент в конец очереди.
SearchItem: Ищет элемент с конкретным ID и возвращает его имя если найден.
SearchItemByName: Ищет элемент с конкретным именем и возвращает его ID если найден.
GetAllItemID: Возвращает массив IDs всех элементов в очереди.
Имплементация этих методов проста, используя рекурсию или циклы для прохождения связанного списка. Например, ClearAll проходит очередь от головы до хвоста, освобождая каждый элемент и обновляя счетчик элементов в очереди. AddItem выделяет новый элемент и добавляет его в конец очереди.
Некоторые предложения по улучшению:
Обработка ошибок: Имплементация не обрабатывает ошибки должным образом. Например, если попытаться найти ID, который не существует в очереди, метод вернет пустую строку или -1. Лучше было бы выбросить исключение вместо этого.
Управление памятью: Имплементация использует new и Dispose для управления памятью, что может привести к утечкам памяти если не использоваться правильно. Рекомендуется использовать умный указатель или сборщик мусора для упрощения управления памятью.
Организация кода: Код организован в отдельные методы для каждой операции, что делает его легко понятным, но может сделать класс труднее использовать. Рекомендуется организовать методы в категории (например, "вставка", "поиск" и т.д.) для улучшения удобства использования.
Безопасность типов: Имплементация использует кастинг типа (TLinkList to RLinkList), что может привести к ошибкам на время выполнения если не сделано правильно. Рекомендуется использовать интерфейсы или абстрактные классы для определения общего интерфейса для элементов связанного списка.
В этом альтернативном решении используется генерируемый тип TList<T> вместо реализации связанного списка вручную:
В этом решении используется класс TList из модуля System.Generics.Collections и определяется custom class RLinkList, которая представляет собой отдельный элемент в связанном списке. Класс TLinkList предоставляет методы для манипуляции связанным списком, такими как добавление и удаление элементов, поиск конкретных элементов и получение всех IDs.
Обратите внимание, что это решение использует оператор new для выделения памяти для каждого элемента, что может привести к утечкам памяти если не использоваться правильно. Рекомендуется использовать умный указатель или сборщик мусора для упрощения управления памятью.
Альтернативой TStringlist является связный список строк, реализованный в виде объекта CTLinkList.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.