16.2. КЛАСС TLIST - СПИСКИ

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

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

Свойства класса:

property List: pPointerList;

Возвращает указатель на массив элементов списка

property Capacity: Integers;

Содержит количество элементов массива указателей списка. Всегда больше Count. Если при добавлении очередного элемента Count стало равно Capacity, происходит автоматическое расширение списка на 16 элементов

property Count: Integer;

Количество элементов списка. Это свойство изменяется при добавлении или удалении элемента

property Items(Index: Integer): Pointers;

Возвращает указатель на элемент списка по его индексу. Самый первый элемент списка имеет индекс 0

 

Тип pPointerList определен следующим образом:

type

pPointerList = PPointerList;

TPointerList = array [0..MaxListSize] of Pointer;

Константа MaxListSize для Delphi 1 ограничена значением 16379 элементов. Для старших версий Delphi она ограничивается доступной памятью.

Следует учесть, что свойство count определяет количество помещенных в список элементов, в то время как capacity - текущую емкость списка. Если при добавлении очередного элемента обнаруживается, что емкость списка исчерпана, происходит наращивание емкости на фиксированную величину (для count < 5 - на 4 элемента, для 4 < count < 8 - на 8, для Count > 7 - на 16). При этом сначала резервируется память для размещения расширенного массива указателей, затем в нее копируется содержимое старого массива, после чего старый массив указателей уничтожается (занимаемая им память возвращается Windows).

Примечание

Если вы заранее знаете, сколько элементов необходимо поместить :в список, установите в начале работы нужное значение в свойство Саpacity - это снизит непроизводительные затраты времени на расширение списка.

Методы класса:

function Add(Item:

Pointer): Integer; procedure Clear;

Добавляет элемент item в конец ci;

вращает его индекс Очищает список, удаляя из него вес Не освобождает память, связанную удаленным элементом. Устанавлив: ства Count и Capacity значение 0

procedure Delete(Index:Integer);

Удаляет из списка элемент с индекс все элементы, расположенные за удаляемым, смещаются на одну позицию вверх

class procedure Er

ror(const Msg: Stringy; Data: Integer); virtual;

Возбуждает исключение ElistErr метрами Msg и Data  

procedure Ex

change (Indexl, Index2:Integer) ;

Меняет местами элементы с индексами index1 иI ndex2

function Expand: TList; function Extract(Item: Pointer): Pointer;

Расширяет массив, увеличивая Capacity Удаляет из списка элемент Item

function First: Pointer;

Возвращает указатель на самый первый элемент списка

function IndexOf(Item:Pointer): Integer;

Отыскивает в списке элемент Item и возвращает его индекс

procedure Insert(Index:

Integer; Item: Pointer) ; 

 

Вставляет элемент Item в позицию Index списка: новый элемент получает индекс Index, все элементы с индексами Index и больше увеличивают свой индекс на 1. При необходимости расширяет список

function Last: Pointer;

 

Возвращает указатель на последний элемент

списка

procedure Move(Curlndex,

Newlndex: Integers;  

Перемещает элемент в списке с позиции CurIndex в позицию Newlndex. Все элементы старого списка с индексами от Curlndex-1 до Newlndex уменьшают свой индекс на 1

procedure Pack;

 

Упаковывает список: удаляет пустые элементы в конце массива индексов

function Remove(Item:

Pointer): Integer;

Отыскивает в списке элемент Item и удаляет его

procedure Sort(Compare: rListSortCompare);

Сортирует коллекцию с помощью функции Compare

Методы Add и insert получают указатель на вставляемый элемент. Чтобы воспользоваться ими, программист должен сам разместить в куче данные и получить соответствующий указатель. Точно так же методы Delete, Remove и Сlear не уничтожают распределенные в памяти данные, которые программист должен, если это необходимо, уничтожить сам.

Например:

var

List: TList;

Item: Pointer;

Value: AnyType;

begin

List := TList.Create; // Создаем список

Item := New(Value); // Размещаем в куче данные

List.Add(Item); // Добавляем элемент к списку .....

List.Remove(Item); // Удаляем элемент из списка

Dispose(Item); // Удаляем его из кучи

List.Free; // Удаляем ненужный список

end;

Метод sort сортирует список по критерию, устанавливаемому функцией compary. Тип TListSortCompare определен следующим образом:

TListSortCompare = function(Iteml, Item2: Pointer): Integer;

Таким образом, функция compare получает указатели на два элемента списка. Результат сравнения:

Критерий сравнения данных устанавливается программистом и реализуется в функции Compare.

В следующем примере в список List помещается 20 случайных вещественных чисел, равномерно распределенных в диапазоне 0...1.

Список сортируется по возрастанию чисел и отображается в компоненте mmOutput (многострочный редактор из учебной формы fmExample).

type

PDouble = ^Double;

Function Comp(Iteml, Item2:. Pointer): Integer;

// С помощью этой функции реализуется сортировка чисел

begin

if PDouble(Iteml)^ < PDouble(Item2) ^ then

Result := -1 else

if PDouble(Iteml^ > PDouble (Item2) ^ then

Result := 1 else

Result := 0 end;

procedure TfmExample.bbRunClick(Sender: TObject);

// Обработчик нажатий кнопки bbRun выполняет основную работу

var

k: Integer;

List: TList;

pD: PDouble;

begin

List := TList.Create; // Создаем список

for k := 1 to 20 do // Наполняем его

begin

New(pD); // Резервируем память

pD^ := Random; // Помещаем в нее случайное число

List.Add(pD); // Добавляем к списку

end/List. Sort (Comp) ; // Сортируем список по возрастанию mmOutput.Lines.Clear;

{ Очищаем редактор mmOutput. В следующем цикле наполняем mmOutput и уничтожаем элементы List }

for k := 0 to List.Count-1 do

begin

pD := List[k]; // Очередное число из списка

mmOutput. Lines .Add (FloatToStr (pD^ );

{Помещаем в mmOutput}

Dispose(pD) // Уничтожаем число

end;

List.Free; // Уничтожаем список

end;