Предположим, вы хотите написать программу для ведения своих личных счетов. Вы можете хранить все данные о счетах в записях, таких как запись типа TCheck. Но при написании программы трудно предположить, с каким количеством счетов вам придется иметь дело. Одно из решений здесь состоит в создании большого массива записей счетов, но это приведет к лишним затратам памяти. Более элегантное и гибкое решение состоит в расширении определения записи и включении в нее указателя на следующую запись списка, что приведет к образованию связанного списка, показанного ниже:
type PCheck = ^TCheck; TCheck = record Amount: Real; Month: 1..12; Day: 1..31; Year: 1990..2000; Payee: string[39]; Next: PCheck; { указывает на следующую запись } end.
Пример 1. Записи в связанном списке.
Теперь вы можете считать каждую запись счета из файла и выделить для нее память. Если запись находится в конце списка, поле Next следует сделать равным nil. В вашей программе требуется отслеживать только два указателя: первый счет в списке и "текущий" счет.
Построение списка
Ниже приведена процедура, которая строит связанный список записей, считывая их из файла. Здесь подразумевается, что вы открыли файл записей TCheck и именем CheckFile, который содержит по крайней мере одну запись.
var ListChecks, CurrentCheck: PCheck;
procedure ReadChecks; begin New(ListOfChecks); { выделить память для первой записи } Read(CheckFile, ListOfChecks^); { считать первую запись } CurrentCheck := ListOfChecks; { сделать первую запись текущей } while not Eof(CheckFile do begin New(CurrentCheck^.Next); { выделить память для следующей записи } Read(CheckFile, CurrentCheck^.Next^); { считать следующую запись } CurrentCheck := CurrentCheck^.Next; { сделать следующую запись текущей } end; CurrentCheck^.Next := nil; { после последней считанной записи следующей нет } end.
Пример 2. Построение связанного списка.
Перемещение по списку
Когда у вас есть список, вы можете легко выполнять поиск в нем конкретной записи. В Примере 8.9 показана функция, которая находит первый счет с конкретной суммой и возвращает указатель на него.
function FindCheckByAmount(AnAmount: Real): PCheck; var Check: PCheck; begin TempCheck := ListOfChecks; { указывает на первую запись } while (Check^.Amount <> AnAmount) and (Check^.Next <> nil) do Check := Check^.Next; if Check^.Amount = AnAmount then FindCheckByAmount := Check { возвращает указатель на найденную запись } else FindCheckByAmount := nil; { или nil, если таких записей нет } end;
Пример 3. Поиск в связанном списке.
Освобождение выделенной для списка памяти
Как показано в процедуре DisposeChecks в Примере 4, вы можете перебрать список, дойдя до каждого элемента и освободив его.
procedure DisposeChecks; var Temp: PCheck; begin CurrentCheck := ListOfChecks; { указывает на первую запись } while CurrentCheck <> nil do begin Temp := CurrentCheck^.Next { сохранить указатель Next } Dispose(CurrentCheck); { освобождение текущей записи } CurrentCheck := Temp; { сделать сохраненную запись текущей } end; end;
Пример 4. Освобождение памяти для связанного списка.
8 8 8
|