Динамические связанные списки

ВВЕДЕНИЕ

 

В рамках предмета «Учебная практика» мы познакомились с концепцией динамических структур данных и алгоритмами работы с ними, а также рассмотрели возможные варианты их практического использования. Наибольшее внимание было уделено такой динамической структуре, как связанный список и различным его дополнениям и модификациям.

В рамках данного проекта сделана попытка решения практической задачи с использованием связанных списков. При проектировании программного средства были учтены особенности работы медицинских учреждений в реальных условиях, в связи с чем введен ряд правил и естественных ограничений. Использование динамических структур данных позволило оптимизировать расход оперативной памяти и организовать гибкое управление данными.

В данной пояснительной записке приведено описание программного средства и процесса его разработки, включающее следующие пункты:

 

- постановка задачи

- описание возможностей приложения

- обоснование выбора структур данных на основе сравнительного анализа возможных вариантов

- схематическое изображение алгоритма

- результаты тестирования программы

- руководство пользователя с подробными пояснениями и иллюстрациями

- заключение

- листинг программы с комментариями

 

1. Постановка задачи
Вариант 6

В магазине имеется список поступивших в продажу CD/DVD дисков. Каждая запись списка содержит: тип хранимой информации (фильм, музыка, СОФТ и т.п.), наименование, автора, цену и примечание (поле м.б. пустым). Требуется:

- Отсортировать внутри каждого типа информацию по наименованию либо по автору (на выбор пользователя);

- Осуществлять поиск диска по автору, по наименованию;

- Предусмотреть возможность добавлять, удалять и корректировать записи из списка, а так же просматривать весь список.


 

2. Выбор и обоснование структур данных

Возможны несколько вариантов представления и хранения необходимых для работы программы данных.

Рассмотрим некоторые из них

 

2.1 Статические массивы.

Массив –это набор однотипных компонентов (элементов), расположенных в памяти непосредственно друг за другом, доступ к которым осуществляется по индексу (индексам).

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

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

Нерационально использовать статические массивы и при необходимости удаления элементов. В этом случае придется производить большое количество дополнительных операций над оставшимися элементами, а также часть занятой памяти останется неиспользованной.

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

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

Таким образом, статические массивы не являются оптимальным решением для представления и хранения данных, необходимых для работы программы.

 

Динамические связанные списки.

Связанный список – это базовая динамическая структура данных, состоящая из узлов, каждый из которых содержит как собственно данные, так и одну или две ссылки («связки») на следующий и/или предыдущий узел списка.

Преимуществом связанных списков по сравнению со статическими массивами является отсутствие ограничений на количество динамически добавляемых элементов (в реальности ограничено только объемом доступной памяти).

Также значительно проще, чем в статических массивах, выполняется процедура удаления.

Недостатком связанных списков является отсутствие возможности произвольного доступа к узлам, т.е. необходимость просмотра всех узлов, предшествующих заданному. Поэтому, в общем случае, работа со списками медленнее, чем с массивами.

К тому же, для хранения указателей на соседние элементы расходуется дополнительное количество памяти.

 

Базы данных.

База данных – это информационная модель, позволяющая упорядоченно хранить данные о группе объектов, обладающих одинаковым набором свойств.

 

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

Множество операций над данными, таких как поиск и фильтрация, с помощью них описываются и выполняются быстрее.

Недостатком баз данных является более низкая скорость работы, т.к. физически база данных представляет собой файл или совокупность файлов, хранимых на внешнем носителе.

Поэтому использование базы данных требует большегообъемапамяти, в т.ч. для хранения служебной информации.

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

 

2.4 Вывод.

Таким образом, проанализировав вышеописанные структуры данных, можно сделать вывод, что в случае поставленной задачи оптимальным решением является использование динамических связанных списков.

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

 

Приведенная ниже схема иллюстрирует структуру хранения данных на базе односвязного динамического списка.

 

Head   PDisk     PDisk   . . . PDisk  

 

Data
Name
Author
Price
Note

 

Data
Name
Author
Price
Note
Data
Name
Author
Price
Note

 

Рисунок 2.1 – Схема структуры данных

 

Предложенная структура данных позволяет динамически добавлять CD/DVD диски в «базу данных», роль которой выполняет связанный список элементов типа PDisk. В программе предусмотрено их редактирование и сохранение изменений.

 

3. Разработка алгоритма

Согласно поставленной задаче алгоритм предусматривает основные возможности работы с данными CD/DVD дисков магазина.

Алгоритм предусматривает следующие возможности:

- добавление в базу данных о CD/DVD дисках (тип, наименование, автор, цена, примечание);

- изменение в базе данных о CD/DVD дисках;

- удаление из базы данных о CD/DVD диске;

- поиск CD/DVD дисков по наименованию либо по автору;

- сортировка списка CD/DVD дисков по наименованию либо по автору;

- автоматическая сортировка списка CD/DVD дисков по их типу при добавлении либо изменение дисков;

- автоматическое сохранение списка CD/DVD дисков в текстовый файл при закрытии программы;

- автоматическая загрузка списка CD/DVD дисков из текстового файла при открытии программы.

Использованные в программе алгоритмы основаны на основных приемах работы с динамическими списками, рассмотренных в соответствующем разделе.


 

 

Рисунок 3.1 – Схема программы

 

Рисунок 3.2 – Схема процедуры добавления диска

 

Рисунок 3.3 – Схема процедуры изменения диска

 

Рисунок 3.4 – Схема процедуры удаления диска

 

 

 

Рисунок 3.5 – Схема процедуры поиска диска

 

 

Рисунок 3.6 – Схема процедуры сортировки дисков

 

 

 

Рисунок 3.7 – Схема процедуры обновления списка дисков

 

 

4. Технические приемы программирования

1) При разработке интерфейса программы были использованы следующие компоненты Delphi: TLabel, TEdit, TCombobox, TButton, TBitBtn, TRadioGroup, TStringGrid, TPanel.

2) В программе используется один динамический список, используемый для хранения данных.

3) Для хранения указателя на начало списка типа PDisk используется глобальная переменная, т.к. доступ к списку должен быть обеспечен в любой точке программы.

4 В программе предусмотрен ряд естественных ограничений (добавление существующего диска, изменение диска на существующий, использование пробелов в поле ''Наименование'' и ''Автор''), реализованных с помощью предварительной проверки состояния списка при клике на соответствующих элементах управления.

5) С целью экономии памяти определена процедура для физического удаления списков.

Пример:

procedure TFrmMain.BtnDeleteClick(Sender: TObject);

var

H, Temp: PDisk;

begin

H := Head;

if Sg.Row <> 0 then

begin

if (H^.Data = Sg.Cells[0, Sg.Row]) and

(H^.Name = Sg.Cells[1, Sg.Row]) and

(H^.Author = Sg.Cells[2, Sg.Row]) and

(inttostr(H^.Price) = Sg.Cells[3, Sg.Row]) and

(H^.Note = Sg.Cells[4, Sg.Row]) then

begin

Temp := Head;

Head := Head^.Next;

Dispose(Temp);

end

else

begin

while (H^.Next^.Data <> Sg.Cells[0, Sg.Row]) or

(H^.Next^.Name <> Sg.Cells[1, Sg.Row]) or

(H^.Next^.Author <> Sg.Cells[2, Sg.Row]) or

(inttostr(H^.Next^.Price) <> Sg.Cells[3, Sg.Row]) or

(H^.Next^.Note <> Sg.Cells[4, Sg.Row]) do

H := H^.Next;

Temp := H^.Next;

H^.Next := H^.Next^.Next;

Dispose(Temp);

end;

GridDeleteRow(Sg.Row);

end;

end;

5. Тестирование

Таблица 5.1 - Результаты тестов подпрограмм

Название подпрограммы Входные данные Ожидаемые результаты Пример вызова Полученные результаты
AddNewDisk Принимает введенные пользователем в поля ввода данные о диске.     Чтение данных, проверка и занесение в список данных о новом диске. Содержимое полей ввода: фильмы; Начало; Кристофер_Нолан; 25000; интереснейший фильм Данные из полей ввода прочитаны, проверены на корректность, в список занесен новый диск, содержащий введенные данные.
Содержимое полей ввода: софт; Total commander; Cristian_ Ghistler; 50000; - Данные из полей ввода прочитаны, проверены на корректность, но в список новый диск не занесен, т.к. поле наименования диска не должно содержать пробелов, выдано соответствующее сообщение.
ChangeDisk Принимает введенные пользователем в поля ввода данные о диске.   Чтение данных, проверка и изменение в списке данных о диске. Содержимое полей ввода: музыка; Жизнь-река; Стас_Михайлов; 30000; эксклюзивное издание Данные из полей ввода прочитаны, проверены на корректность, в списке изменились данные диска.
Содержимое полей ввода: фильмы; Начало; Кристофер_Нолан; 25000; интереснейший фильм Данные из полей ввода прочитаны, проверены на корректность, в списке данные диска не изменились, т.к. диск с такими данными уже имеется, выдано соответствующее сообщение.
DeleteDisk Принимает данные о диске из полей выделенной строки таблицы. Поиск и удаление из списка диска с заданными данными. Содержимое полей строки таблицы: фильмы; Начало; Кристофер_Нолан; 25000; интереснейший фильм Был найден и удален из списка диск с заданными данными.
SearchByName Принимает введенное пользователем в поле ввода наименование диска.   Чтение введенных данных, вывод на экран найденных по данному запросу дисков. Содержимое поля ввода: жизнь Данные прочитаны, поиск диска с наименованием, содержащим введенное, на экран был выведен диск .
Содержимое поля ввода: белазар Данные прочитаны, поиск диска с наименованием, содержащим введенное, на экран не было выведен диск, т.к. диска с заданным наименованием нет в списке, выдано соответствующее сообщение.
SortByName   Сортирует список дисков по наименованию в алфавитном порядке.   Список успешно отсортировался.

6. Руководство пользователя

При запуске программы появляется главное окно(рис 6.1).

Рисунок 6.1

На главном окне можно видеть таблицу, а также операции, выполняемые над её элементами. Если после предыдущего запуска программы были сохранены диски, то они автоматически загружаются в таблицу(рис 6.2).

 

Рисунок 6.2

 

В программе доступны следующие операции над дисками:

1. Добавить

2. Изменить

3. Удалить

4. Поиск

5. Сортировка

 

Добавить диск

Для добавления диска в список нажмите на кнопку "Добавить" на панели операций, заполните обязательные поля в открывшейся форме(рис 6.3) и нажмите "Добавить".

Рисунок 6.3

При неверном вводе данных диска могут появиться следующие сообщения об ошибках:

1) При добавлении диска, который уже есть в списке; при изменении диска на такой, который уже есть в списке(рис 6.4):

 

 

Рисунок 6.4

2) При добавлении диска, содержащего пробел в поле "наименование" или "автор"(рис 6.5):

 

 

Рисунок 6.5

3) При добавлении или изменении диска с незаполненным полем(полями):

 

 

Рисунок 6.6

 

Изменить диск

Для изменения диска выделите строку таблицы, содержащую данные интересующего вас диска, нажмите на кнопку "Изменить" на панели операций, исправьте интересующие вас поля в открывшейся форме(рис 6.7) и нажмите "Изменить".

Рисунок 6.7

При неправильном вводе данных могут возникнуть сообщения об ошибках, описанные в предыдущем подпункте.

 

Удалить диск

Выделите строку в таблице с данными ненужного вам диска и нажмите на кнопку "Удалить" на панели операций(рис 6.8).

 

Рисунок 6.8

 

Поиск диска

Введите наименование или автора диска в соответствующее поле поиска на панели поиска(рис 6.9) и нажмите "ok" для отображения интересующего вас диска(дисков). Для просмотра всего списка дисков и очистки полей поиска нажмите на кнопку "Обновить"(рис 6.10).

 

Рисунок 6.9

 

Рисунок 6.10

При поиске несуществующего в списке диска появляется сообщение(рис 6.11):

Рисунок 6.11

Сортировка дисков

Для сортировки списка по наименованию или по автору выберите соответствующий пункт на панели сортировки(6.12).

 

Рисунок 6.12

 

По закрытию программы, данные списка дисков автоматически записываются в файл. При следующем запуске программы они будут загружены из файла.


7.Заключение

Как было показано выше, данное приложение предоставляет пользователю возможности, перечисленные при постановке задачи.

При этом для решения задачи использованы структуры данных (динамические связанные списки), выбор которых обоснован в пункте «Выбор и обоснование структур данных». Разработанный алгоритм, созданный при помощи среды программирования Delphi, эффективно использует предоставляемые данной средой возможности. Таким образом, в процессе разработки данного программного средства мы на практике убедились в преимуществах работы с динамическими структурами данных.

В результате тестирования приложения было показано, что полученные результаты работы подпрограмм на конкретных рассмотренных (корректных и некорректных) наборах данных соответствуют ожидаемым, т. е. основные подпрограммы функционируют нормально.

В программе предусмотрен ряд естественных ограничений, продиктованных смыслом поставленной задачи и особенностями ее реализации в действительности. Данные ограничения подробно документированы в пункте «Руководство пользователя».

Ниже приведен листинг программы с подробными комментариями.

Таким образом, данное приложение соответствует задаче, указанной в пункте 1 «Постановка задачи».

 

8.Листингпрограммы

unit Unit1;

 

interface

 

uses

Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,

System.Classes, Vcl.Graphics,

Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.Grids, Vcl.Buttons, unit2;

 

type

PDisk = ^Disk;

 

Disk = Record

Data: string;

Name: string;

Author: string;

Price: integer;

Note: string;

Next: PDisk;

End;

 

TFrmMain = class(TForm)

Sg: TStringGrid;

PnlActions: TPanel;

BtnAdd: TButton;

BtnChange: TButton;

BtnDelete: TButton;

EdtAuthorSearch: TEdit;

BtnNameSearch: TButton;

EdtNameSearch: TEdit;

BtnAuthorSearch: TButton;

Rg: TRadioGroup;

LblSearch: TLabel;

LblOperations: TLabel;

PnlOperations: TPanel;

PnlSearch: TPanel;

BtnRefresh: TBitBtn;

procedure FormCreate(Sender: TObject);

procedure BtnAddClick(Sender: TObject);

procedure BtnChangeClick(Sender: TObject);

procedure BtnDeleteClick(Sender: TObject);

procedure BtnNameSearchClick(Sender: TObject);

procedure BtnRefreshClick(Sender: TObject);

procedure BtnAuthorSearchClick(Sender: TObject);

procedure RgClick(Sender: TObject);

procedure FormClose(Sender: TObject; var Action: TCloseAction);

procedure SgDrawCell(Sender: TObject; ACol, ARow: integer; Rect: TRect;

State: TGridDrawState);

private

{ Private declarations }

public

procedure Sort(SortType: integer);

{ Public declarations }

end;

 

var

FrmMain: TFrmMain;

Head: PDisk;

Correct: Boolean = true;

IsAdded: Boolean;

 

implementation

 

{$R *.dfm}

 

 

// процедура создания сортированного списка

procedure TFrmMain.Sort(SortType: integer);

var

H, N, NewHead, Temp: PDisk;

DiskType, NewDiskType, RowNum, ColNum: integer;

CurName, NewName: String;

begin

H := Head;

NewHead := nil;

// выполнять, пока не пройдёмся по всему текущему списку

while H <> nil do

begin

// DiskType - числовое значение типа текущего диска

if H^.Data = 'фильмы' then

DiskType := 0

else if H^.Data = 'музыка' then

DiskType := 1

else

DiskType := 2;

// если сортированный список не существует, то создаём

if NewHead = nil then

begin

New(NewHead);

NewHead^ := H^;

NewHead^.Next := nil;

end

else

// если сортированный список существует

begin

N := NewHead;

// NewDiskType - числовое значение типа диска из сортированного списка

if N^.Data = 'фильмы' then

NewDiskType := 0

else if N^.Data = 'музыка' then

NewDiskType := 1

else

NewDiskType := 2;

{ если сортированный список состоит только из 1го элемента и у диска из

сортированного списка приоритет выше чем у текущего, то добавляем

текущий после сортированного }

if (DiskType > NewDiskType) and (NewHead^.Next = nil) then

begin

New(N^.Next);

N^.Next^ := H^;

N^.Next^.Next := nil;

end

else

// если предыдущее условие не выполнено

begin

// если DiskType = NewDiskType, т.е. приоритеты дисков равны и список состоит из 1го диска

if NewHead^.Next = nil then

begin

{ SortType = 0, если сортируем по наименованию, 1 - если по автору.

CurName и NewName - строковые величины, которые будут сравниваются,

и в зависимости от типа сортировки могут обозначать

наименование(0) или автора(1) диска, CurName - текущий диск,

NewName - диск из сортированного списка }

if SortType = 0 then

begin

CurName := H^.Name;

NewName := N^.Name;

end

else

begin

CurName := H^.Author;

NewName := N^.Author;

end;

// добавляем в сортированный список элемент(диск) из текущего

if AnsiLowerCase(CurName) > AnsiLowerCase(NewName) then

begin

New(NewHead^.Next);

NewHead^.Next^ := H^;

NewHead^.Next^.Next := nil;

end

else

begin

Temp := NewHead;

New(NewHead);

NewHead^ := H^;

NewHead^.Next := Temp;

end;

end

// если в сортированном списке элементов больше, чем 1

else

begin

// обновляем приоритет диска из нового списка и сравниваемые величины

if N^.Data = 'фильмы' then

NewDiskType := 0

else if N^.Data = 'музыка' then

NewDiskType := 1

else

NewDiskType := 2;

if SortType = 0 then

begin

CurName := H^.Name;

NewName := N^.Name;

end

else

begin

CurName := H^.Author;

NewName := N^.Author;

end;

// проверяем 1ый элемент сортированного списка

if (DiskType = NewDiskType) and

(AnsiLowerCase(CurName) < AnsiLowerCase(NewName)) then

begin

Temp := NewHead;

New(NewHead);

NewHead^ := H^;

NewHead^.Next := Temp;

end

else

// проверяем остальные элементы

begin

repeat

// если следующего за отсортированным диском не существует, то добавляем после сортированного текущий

if N^.Next = nil then

begin

New(N^.Next);

N^.Next^ := H^;

N^.Next^.Next := nil;

break;

end;

// обновляем сравниваемые величины

if SortType = 0 then

begin

CurName := H^.Name;

NewName := N^.Next^.Name;

end

else

begin

CurName := H^.Author;

NewName := N^.Next^.Author;

end;

{ если (приоритеты текущего диска и следующего сортированного диска

равны и не выполняется условие строкового(алфавитного) сравнения) или

(приоритет текущего диска больше приоритета следующего за сортированным

диска),то переходим на следующий сортированный диск и обновляем приоритет }

if ((DiskType = NewDiskType) and

(AnsiLowerCase(CurName) > AnsiLowerCase(NewName))) or

(DiskType > NewDiskType) then

begin

N := N^.Next;

if N^.Next <> nil then

begin

if N^.Next^.Data = 'фильмы' then

NewDiskType := 0

else if N^.Next^.Data = 'музыка' then

NewDiskType := 1

else

NewDiskType := 2;

end;

end

else

{ иначе, если (приоритеты текущего диска и следующего сортированного диска не

равны или выполняется условие строкового(алфавитного) сравнения) или

(приоритет текущего диска равен приоритету следующего за сортированным

диска),то добавляем текущий диск к сортированным }

begin

Temp := N^.Next;

New(N^.Next);

N^.Next^ := H^;

N^.Next^.Next := Temp;

break;

end;

// повторяем, пока не пройдемся по всему сортированному списку

until N = nil;

end;

end;

end;

end;

// переходим на следующий элемент(диск) текущего списка

H := H^.Next;

{ если прошлись уже по всему текущему списку, значит отсортированный список

готов, неотсортированный список больше не нужен, удаляем его

для экономии памяти(повышение эффективности программы) }

end;

if Head <> nil then

begin

while Head <> nil do

begin

Temp := Head;

Head := Head^.Next;

Dispose(Temp);

end;

Head := NewHead;

// печать отсортированного списка

if IsAdded = true then

Sg.RowCount := Sg.RowCount + 1;

H := Head;

with FrmMain do

for RowNum := 1 to Sg.RowCount - 1 do

begin

for ColNum := 0 to 4 do

begin

case ColNum of

0:

Sg.Cells[ColNum, RowNum] := H^.Data;

1:

Sg.Cells[ColNum, RowNum] := H^.Name;

2:

Sg.Cells[ColNum, RowNum] := H^.Author;

3:

Sg.Cells[ColNum, RowNum] := inttostr(H^.Price);

4:

Sg.Cells[ColNum, RowNum] := H^.Note;

end;

end;

H := H^.Next;

end;

end;

end;

 

// при нажатии на кнопку 'Добавить'

procedure TFrmMain.BtnAddClick(Sender: TObject);

begin

with FrmNewDisk do

begin

// очищаем поля компонентов на второй форме

CmbDiskType.ItemIndex := 0;

EdtName.Text := '';

EdtAuthor.Text := '';

EdtPrice.Text := '';

EdtNote.Text := '';

BtnAddNewDisk.Visible := true;

BtnChangeDisk.Visible := false;

IsAdded := true;

// открываем вторую форму

FrmNewDisk.ShowModal;

end;

end;

 

// процедура печати результата поиска

procedure PrintSearch(Searching: string; T: integer);

var

H, Temp, PrintDisk: PDisk;

Comparing: string;

begin

with FrmNewDisk do

with FrmMain do

begin

// PrintDisk - список дисков, которые удовлетворяют условию поиска

PrintDisk := nil;

H := Head;

// проходимся по всему списку

while H <> nil do

begin

{ параметр T передаём при вызове процедуры, если он = 1,

то ищем диски по наименованию, иначе по автору.

Comparing - наименование/автор текущего диска,

Searching - наименование/автор, которого мы хотим найти }

if T = 1 then

Comparing := H^.Name

else

Comparing := H^.Author;

// если строка Searching является строкой/подстрокой строки Comparing

if Pos(AnsiLowerCase(Searching), AnsiLowerCase(Comparing)) <> 0 then

begin

// если PrintDisk пустой, то создаём его и добавляем 1ый элемент(диск)

if PrintDisk = nil then

begin

New(PrintDisk);

PrintDisk^ := H^;

PrintDisk^.Next := nil;

end

else

// если не пустой, то добавляем элемент

begin

Temp := PrintDisk;

while Temp^.Next <> nil do

Temp := Temp^.Next;

New(Temp^.Next);

Temp^.Next^ := H^;

Temp^.Next^.Next := nil;

end;

end;

// проверяем следующий элемент(диск) списка

H := H^.Next;

end;

{ после того, как проверили весь список, если PrintDisk пустой,

показать соответствующее сообщение }

if PrintDisk = nil then

ShowMessage('По данному запросу дисков не найдено.')

else

begin

{ если PrintDisk не пустой, то выводим все его элементы на экран,

последовательно удаляя элементы PrintDisk'a для экономии памяти

(повышение эффективности программы) }

Sg.RowCount := 1;

while PrintDisk <> nil do

begin

Sg.RowCount := Sg.RowCount + 1;

Sg.Cells[0, Sg.RowCount - 1] := PrintDisk^.Data;

Sg.Cells[1, Sg.RowCount - 1] := PrintDisk^.Name;

Sg.Cells[2, Sg.RowCount - 1] := PrintDisk^.Author;

Sg.Cells[3, Sg.RowCount - 1] := inttostr(PrintDisk^.Price);

Sg.Cells[4, Sg.RowCount - 1] := PrintDisk^.Note;

Temp := PrintDisk;

PrintDisk := PrintDisk^.Next;

Dispose(Temp);

end;

end;

end;

end;

 

// процедура поиска и вывода на экран дисков, поиск производится по автору

procedure TFrmMain.BtnAuthorSearchClick(Sender: TObject);

begin

PrintSearch(EdtAuthorSearch.Text, 2);

end;

 

// при нажатии на кнопку 'Изменить'

procedure TFrmMain.BtnChangeClick(Sender: TObject);

var

H, Temp: PDisk;

RowNum, ColNum: integer;

begin

with FrmNewDisk do

begin

// если выделили не заглавную строку таблицы

if Sg.Row <> 0 then

begin

{ переносим значения из ячеек строки выделенной таблицы в поля компонентов

на другой форме для дальнейшей работы с изменяемым элементом списка(диском) }

if Sg.Cells[0, Sg.Row] = 'фильмы' then

CmbDiskType.ItemIndex := 0;

if Sg.Cells[0, Sg.Row] = 'музыка' then

CmbDiskType.ItemIndex := 1;

if Sg.Cells[0, Sg.Row] = 'софт' then

CmbDiskType.ItemIndex := 2;

EdtName.Text := Sg.Cells[1, Sg.Row];

EdtAuthor.Text := Sg.Cells[2, Sg.Row];

EdtPrice.Text := Sg.Cells[3, Sg.Row];

EdtNote.Text := Sg.Cells[4, Sg.Row];

BtnAddNewDisk.Visible := false;

BtnChangeDisk.Visible := true;

Correct := false;

// открываем вторую форму для корректировки диска

FrmNewDisk.ShowModal;

// если изменения не были произведены, тогда выходим из процедуры

if Correct = false then

begin

Exit;

end

else

// иначе

begin

H := Head;

// если корректируем 1ую строку (1ый диск списка)}

if Sg.Row = 1 then

begin

// если диск стал иметь тип 'фильмы'

if CmbDiskType.Text = 'фильмы' then

begin

H^.Data := CmbDiskType.Text;

H^.Name := EdtName.Text;

H^.Author := EdtAuthor.Text;

H^.Price := strtoint(EdtPrice.Text);

H^.Note := EdtNote.Text;

{ если ни одна из сортировок не активирована,

то меняем значенияполей в 1ой строке таблицы }

if Rg.ItemIndex = -1 then

begin

Sg.Cells[0, 1] := CmbDiskType.Text;

Sg.Cells[1, 1] := EdtName.Text;

Sg.Cells[2, 1] := EdtAuthor.Text;

Sg.Cells[3, 1] := EdtPrice.Text;

Sg.Cells[4, 1] := EdtNote.Text;

ShowMessage('Диск успешно отредактирован.');

Exit;

end;

end;

// если диск стал иметь тип 'музыка'

if CmbDiskType.Text = 'музыка' then

begin

// запоминаем в Temp меняющуюся строку, текущий диск извлекается из списка

Temp := H;

H := H^.Next;

Head := Head^.Next;

Temp^.Data := CmbDiskType.Text;

Temp^.Name := EdtName.Text;

Temp^.Author := EdtAuthor.Text;

Temp^.Price := strtoint(EdtPrice.Text);

Temp^.Note := EdtNote.Text;

{ если тип первого элемента(диска) списка 'музыка',

то Temp добавляется в список как 1ый диск }

if H^.Data = 'музыка' then

begin

Temp^.Next := H;

Head := Temp;

end

else

// иначе

begin

// если следующий диск в списке существует

if H^.Next <> nil then

// пока тип следующего диска не 'музыка' или не 'софт'

while (H^.Next^.Data <> 'музыка') and

(H^.Next^.Data <> 'софт') do

begin

{ если следующий диск не является последним в списке,

то переходим к следующему }

if H^.Next^.Next <> nil then

H := H^.Next

else

// иначе переходим к следующему и выходим из цикла

begin

H := H^.Next;

break;

end;

end;

// добавляем диск Temp как следующий за текущим

Temp^.Next := H^.Next;

H^.Next := Temp;

end;

end;

// если диск стал иметь тип 'софт'

if CmbDiskType.Text = 'софт' then

begin

// запоминаем в Temp меняющуюся строку, текущий диск извлекается из списка

Temp := H;

H := H^.Next;

Head := Head^.Next;

Temp^.Data := CmbDiskType.Text;

Temp^.Name := EdtName.Text;

Temp^.Author := EdtAuthor.Text;

Temp^.Price := strtoint(EdtPrice.Text);

Temp^.Note := EdtNote.Text;

{ если тип первого элемента(диска) списка 'софт',

то Temp добавляется в список как 1ый диск }

if Head^.Data = 'софт' then

begin

Temp^.Next := Head;

Head := Temp;

end

else

// иначе

begin

// если следующий диск в списке существует

if H^.Next <> nil then

// пока тип следующего диска не 'софт'

while H^.Next^.Data <> 'софт' do

begin

{ если следующий диск не является последним в списке,

то переходим к следующему }

if H^.Next^.Next <> nil then

H := H^.Next

else

// иначе переходим к следующему и выходим из цикла

begin

H := H^.Next;

break;

end;

end;

// добавляем диск Temp как следующий за текущим

Temp^.Next := H^.Next;

H^.Next := Temp;

end;

end;

end

else

// если корректируем не 1ую строку (не 1ый диск списка)}

begin

// запоминаем в Temp меняющуюся строку, текущий диск извлекается из списка

while (H^.Next^.Data <> Sg.Cells[0, Sg.Row]) or

(H^.Next^.Name <> Sg.Cells[1, Sg.Row]) or

(H^.Next^.Author <> Sg.Cells[2, Sg.Row]) or

(inttostr(H^.Next^.Price) <> Sg.Cells[3, Sg.Row]) or

(H^.Next^.Note <> Sg.Cells[4, Sg.Row]) do

H := H^.Next;

Temp := H^.Next;

H^.Next := H^.Next^.Next;

Temp^.Data := CmbDiskType.Text;

Temp^.Name := EdtName.Text;

Temp^.Author := EdtAuthor.Text;

Temp^.Price := strtoint(EdtPrice.Text);

Temp^.Note := EdtNote.Text;

// вставляем её на вершину своего типа

// если диск стал иметь тип 'фильмы'

if CmbDiskType.Text = 'фильмы' then

begin

Temp^.Next := Head;

Head := Temp;

end;

// если диск стал иметь тип 'музыка'

if CmbDiskType.Text = 'музыка' then

begin

H := Head;

{ если тип первого элемента(диска) списка 'музыка',

то Temp добавляется в список как 1ый диск }

if Head^.Data = 'музыка' then

begin

Temp^.Next := Head;

Head := Temp;

end

else

// иначе

begin

// если следующий диск в списке существует

if H^.Next <> nil then

// пока тип следующего диска не 'музыка' или не 'софт'

while (H^.Next^.Data <> 'музыка') and

(H^.Next^.Data <> 'софт') do

begin

{ если следующий диск не является последним в списке,

то переходим к следующему }

if H^.Next^.Next <> nil then

H := H^.Next

else

// иначе переходим к следующему и выходим из цикла

begin

H := H^.Next;

break;

end;

end;

// добавляем диск Temp как следующий за текущим

Temp^.Next := H^.Next;

H^.Next := Temp;

end;

end;

// если диск стал иметь тип 'софт'

if CmbDiskType.Text = 'софт' then

begin

H := Head;

{ если тип первого элемента(диска) списка 'софт',

то Temp добавляется в список как 1ый диск }

if Head^.Data = 'софт' then

begin

Temp^.Next := Head;

Head := Temp;

end

else

// иначе

begin

// если следующий диск в списке существует

if H^.Next <> nil then

// пока тип следующего диска не 'софт'

while H^.Next^.Data <> 'софт' do

begin

{ если следующий диск не является последним в списке,

то переходим к следующему }

if H^.Next^.Next <> nil then

H := H^.Next

else

// иначе переходим к следующему и выходим из цикла

begin

H := H^.Next;

break;

end;

end;

// добавляем диск Temp как следующий за текущим

Temp^.Next := H^.Next;

H^.Next := Temp;

end;

end;

end;

{ если активирована сортировка по наименованию, сортируем

соответствующим образом и выводим на экран список }

if Rg.ItemIndex = 0 then

begin

IsAdded := false;

Sort(0);

ShowMessage('Диск успешно отредактирован.');

Exit;

end;

{ если активирована сортировка по автору, сортируем

соответствующим образом и выводим на экран список }

if Rg.ItemIndex = 1 then

begin

IsAdded := false;

Sort(1);

ShowMessage('Диск успешно отредактирован.');

Exit;

end;

// если никакая сортировка не активирована, то выводим на экран список

H := Head;

for RowNum := 1 to Sg.RowCount - 1 do

begin

for ColNum := 0 to 4 do

begin

case ColNum of

0:

Sg.Cells[ColNum, RowNum] := H^.Data;

1:

Sg.Cells[ColNum, RowNum] := H^.Name;

2:

Sg.Cells[ColNum, RowNum] := H^.Author;

3:

Sg.Cells[ColNum, RowNum] := inttostr(H^.Price);

4:

Sg.Cells[ColNum, RowNum] := H^.Note;

end;

end;

H := H^.Next;

end;

ShowMessage('Диск успешно отредактирован.');

end;

end;

end;

end;

 

// удаление строки из таблицы

procedure GridDeleteRow(RowNumber: integer);

var

i: integer;

begin

with FrmMain do

begin

Sg.Row := RowNumber;

// если удаляется последняя строка таблицы

if Sg.Row = Sg.RowCount - 1 then

Sg.RowCount := Sg.RowCount - 1

else

begin

// не последняя

for i := RowNumber to Sg.RowCount - 1 do

Sg.Rows[i] := Sg.Rows[i + 1];

Sg.RowCount := Sg.RowCount - 1;

end;

end;

end;

 

// при нажатии на кнопку 'Удалить'

procedure TFrmMain.BtnDeleteClick(Sender: TObject);

var

H, Temp: PDisk;

begin

H := Head;

// если выделена не заглавная строка таблицы

if Sg.Row <> 0 then

begin

{ если данные первого в списке диска совпадают с данными диска

выделенной строки таблицы, то удаляем первый элемент(диск) из списка,

а также очищаем занимаемую им память }

if (H^.Data = Sg.Cells[0, Sg.Row]) and (H^.Name = Sg.Cells[1, Sg.Row]) and

(H^.Author = Sg.Cells[2, Sg.Row]) and

(inttostr(H^.Price) = Sg.Cells[3, Sg.Row]) and

(H^.Note = Sg.Cells[4, Sg.Row]) then

begin

Temp := Head;

Head := Head^.Next;

Dispose(Temp);

end

else

{ в противном случае ищем совпадения данных текущего диска с данными диска

в выделенной строке таблицы, после чего удаляем этот элемент(диск) из списка

и очищаем занимаемую им память }

begin

while (H^.Next^.Data <> Sg.Cells[0, Sg.Row]) or

(H^.Next^.Name <> Sg.Cells[1, Sg.Row]) or

(H^.Next^.Author <> Sg.Cells[2, Sg.Row]) or

(inttostr(H^.Next^.Price) <> Sg.Cells[3, Sg.Row]) or

(H^.Next^.Note <> Sg.Cells[4, Sg.Row]) do

H := H^.Next;

Temp := H^.Next;

H^.Next := H^.Next^.Next;

Dispose(Temp);

end;

// после физического удаления элемента(диска) из списка удаляем данные о нём из таблицы

GridDeleteRow(Sg.Row);

end;

end;

 

// процедура поиска и вывода на экран дисков, поиск производится по наименованию

procedure TFrmMain.BtnNameSearchClick(Sender: TObject);

begin

PrintSearch(EdtNameSearch.Text, 1);

end;

 

{ при нажатии на кнопку 'Обновить' выводит на экран весь список,

а также очищает поля поиска }

procedure TFrmMain.BtnRefreshClick(Sender: TObject);

var

H: PDisk;

begin

H := Head;

Sg.RowCount := 1;

while H <> nil do

begin

Sg.RowCount := Sg.RowCount + 1;

Sg.Cells[0, Sg.RowCount - 1] := H^.Data;

Sg.Cells[1, Sg.RowCount - 1] := H^.Name;

Sg.Cells[2, Sg.RowCount - 1] := H^.Author;

Sg.Cells[3, Sg.RowCount - 1] := inttostr(H^.Price);

Sg.Cells[4, Sg.RowCount - 1] := H^.Note;

H := H^.Next;

end;

EdtNameSearch.Text := '';

EdtAuthorSearch.Text := '';

end;

 

// при закрытие формы

procedure TFrmMain.FormClose(Sender: TObject; var Action: TCloseAction);

var

F: TextFile;

begin

AssignFile(F, 'Data.txt');

if Head <> nil then

begin

// создаём новый файл

Rewrite(F);

// проходимся по каждому диску списка

while Head <> nil do

begin

// записываем информацию о диске в файл

if Head^.Data = 'фильмы' then

write(F, '0 ')

else if Head^.Data = 'музыка' then

write(F, '1 ')

else

write(F, '2 ');

write(F, Head^.Name, ' ');

write(F, Head^.Author, ' ');

write(F, inttostr(Head^.Price), ' ');

{ если текущий диск является последним, то просто дописываем в файл последнее поле диска('примечание') }

if Head^.Next = nil then

write(F, Head^.Note)

else

{ если текущий диск не является последним в списке, то после записи последнего

поля диска('примечание') в файл переходим на следующую строку файла }

writeln(F, Head^.Note);

// переходим к следующему диску

Head := Head^.Next;

end;

// закрываем файл

CloseFile(F);

end

else if FileExists('Data.txt') then

Erase(F);

end;

 

// при создании формы

procedure TFrmMain.FormCreate(Sender: TObject);

var

F: TextFile;

C: char;

S: string;

H: PDisk;

i: integer;

begin

{ присваиваем заглавным ячейкам таблицы имена,

а также устанавливаем ширину некоторых её столбцов }

Sg.ColWidths[1] := 250;

Sg.ColWidths[2] := 150;

Sg.ColWidths[4] := 495;

Sg.Cells[0, 0] := ' Тип';

Sg.Cells[1, 0] := ' Наименование';

Sg.Cells[2, 0] := ' Автор';

Sg.Cells[3, 0] := ' Цена';

Sg.Cells[4, 0] :=

' Примечание';

// если существует файл с данными

if FileExists('Data.txt') then

begin

// открываем файл F для чтения

AssignFile(F, 'Data.txt');

Reset(F);

// i - номер печатающейся строки

i := 1;

// пока не конец файла

while not Eof(F) do

begin

// если список пуст

if Head = nil then

begin

// создаём список, считываем данные о первом диске из файла

New(Head);

Read(F, C);

case strtoint(C) of

0:

Head^.Data := 'фильмы';

1:

Head^.Data := 'музыка';

2:

Head^.Data := 'софт';

end;

Read(F, C, C);

S := '';

while C <> ' ' do

begin

S := S + C;

Read(F, C);

end;

Head^.Name := S;

S := '';

Read(F, C);

while C <> ' ' do

begin

S := S + C;

Read(F, C);

end;

Head^.Author := S;

S := '';

Read(F, C);

while C <> ' ' do

begin

S := S + C;

Read(F, C);

end;

Head^.Price := strtoint(S);

S := '';

Read(F, C);

while not((Ord(C) = 13) or (Ord(C) = 26)) do

begin

S := S + C;

Read(F, C);

end;

Head^.Note := S;

Head^.Next := nil;

// вывод списка(первого элемента) на экран

Sg.RowCount := Sg.RowCount + 1;

Sg.Cells[0, 1] := Head^.Data;

Sg.Cells[1, 1] := Head^.Name;

Sg.Cells[2, 1] := Head^.Author;

Sg.Cells[3, 1] := inttostr(Head^.Price);

Sg.Cells[4, 1] := Head^.Note;

end

else

// если список не пуст

begin

// добавляем диск в список, считывая данные о нём из файла

Readln(F);

H := Head;

while H^.Next <> nil do

H := H^.Next;

New(H^.Next);

H := H^.Next;

Read(F, C);

case strtoint(C) of

0:

H^.Data := 'фильмы';

1:

H^.Data := 'музыка';

2:

H^.Data := 'софт';

end;

Read(F, C, C);

S := '';

while C <> ' ' do

begin

S := S + C;

Read(F, C);

end;

H^.Name := S;

S := '';

Read(F, C);

while C <> ' ' do

begin

S := S + C;

Read(F, C);

end;

H^.Author := S;

S := '';

Read(F, C);

while C <> ' ' do

begin

S := S + C;

Read(F, C);

end;

H^.Price := strtoint(S);

S := '';

Read(F, C);

while not((Ord(C) = 13) or (Ord(C) = 26)) do

begin

S := S + C;

Read(F, C);

end;

H^.Note := S;

H^.Next := nil;

// вывод на экран очередного диска

Sg.RowCount := Sg.RowCount + 1;

i := i + 1;

Sg.Cells[0, i] := H^.Data;

Sg.Cells[1, i] := H^.Name;

Sg.Cells[2, i] := H^.Author;

Sg.Cells[3, i] := inttostr(H^.Price);

Sg.Cells[4, i] := H^.Note;

end;

end;

// закрываем файл

CloseFile(F);

end;

end;

 

// при нажатии на вид сортировки

procedure TFrmMain.RgClick(Sender: TObject);

begin

IsAdded := false;

if Rg.ItemIndex = 0 then

// сортируем по наименованию

Sort(0);

if Rg.ItemIndex = 1 then

// сортируем по автору

Sort(1);

end;

 

end.

 

 

unit Unit2;

 

interface

 

uses

Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,

System.Classes, Vcl.Graphics,

Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Grids;

 

type

 

TFrmNewDisk = class(TForm)

EdtName: TEdit;

CmbDiskType: TComboBox;

EdtAuthor: TEdit;

EdtPrice: TEdit;

EdtNote: TEdit;

BtnAddNewDisk: TButton;

BtnChangeDisk: TButton;

LblData: TLabel;

LblName: TLabel;

LblAuthor: TLabel;

LblPrice: TLabel;

LblNote: TLabel;

procedure BtnAddNewDiskClick(Sender: TObject);

procedure BtnChangeDiskClick(Sender: TObject);

private

{ Private declarations }

public

{ Public declarations }

end;

 

var

FrmNewDisk: TFrmNewDisk;

 

implementation

 

{$R *.dfm}

 

uses unit1;

 

{ функция проверки списка на наличие диска с полями, заполненными так же,

как поля компонентов формы }

function CheckDisk(H: PDisk): boolean;

var

s: string;

begin

Result := false;

with FrmNewDisk do

// проходимся по всему списку

while H <> nil do

begin

case CmbDiskType.ItemIndex of

0:

s := 'фильмы';

1:

s := 'музыка';

2:

s := 'софт';

end;

{ если в списке имеется диск с полями, заполненными так же,

как поля компонентов формы, тогда функции присваивается

соответственный результат, а также выходим из функции }

if (H^.Data = s) and (H^.Name = EdtName.Text) and

(H^.Author = EdtAuthor.Text) and (inttostr(H^.Price) = EdtPrice.Text)

and (H^.Note = EdtNote.Text) then

begin

Result := true;

Exit;

end

else

// иначе проверяем следующий элемент

H := H^.Next;

end;

end;

 

// процедура добавления диска в список

procedure AddDisk(H: PDisk);

var

i, j: integer;

Temp: PDisk;

begin

{ если в списке имеется диск с полями, заполненными так же,

как поля компонентов формы, выводим соответствующее сообщение }

if CheckDisk(Head) = true then

begin

ShowMessage('Данный диск уже имеется.');

Exit;

end

else

// иначе

with FrmNewDisk do

// если список не существует

if H = nil then

begin

// создаём список

New(Head);

with Head^ do

begin

case CmbDiskType.ItemIndex of

0:

Data := 'фильмы';

1:

Data := 'музыка';

2:

Data := 'софт';

end;

Name := EdtName.Text;

Author := EdtAuthor.Text;

Price := strtoint(EdtPrice.Text);

Note := EdtNote.Text;

Next := nil;

with FrmMain do

begin

// вывод на экран списка, состоящего из 1 элемента(диска)

Sg.RowCount := Sg.RowCount + 1;

Sg.Cells[0, Sg.RowCount - 1] := Head^.Data;

Sg.Cells[1, Sg.RowCount - 1] := Head^.Name;

Sg.Cells[2, Sg.RowCount - 1] := Head^.Author;

Sg.Cells[3, Sg.RowCount - 1] := inttostr(Head^.Price);

Sg.Cells[4, Sg.RowCount - 1] := Head^.Note;

ShowMessage('CD/DVD диск добавлен.');

end;

end;

end

else

begin

// если список существует и добавляем фильм, то добавляем элемент(диск) в список

if CmbDiskType.ItemIndex = 0 then

begin

New(H);

H^.Data := 'фильмы';

H^.Name := EdtName.Text;

H^.Author := EdtAuthor.Text;

H^.Price := strtoint(EdtPrice.Text);

H^.Note := EdtNote.Text;

H^.Next := Head;

Head := H;

with FrmMain do

begin

{ если активирована сортировка по наименованию, сортируем

соответствующим образом и выводим на экран список }

if Rg.ItemIndex = 0 then

begin

Sort(0);

ShowMessage('CD/DVD диск добавлен.');

Exit;

end;

{ если активирована сортировка по автору, сортируем

соответствующим образом и выводим на экран список }

if Rg.ItemIndex = 1 then

begin

Sort(1);

ShowMessage('CD/DVD диск добавлен.');

Exit;

end;

{ если никакая сортировка не активирована,

вставляем в таблицу добавленный элемент(диск) }

Sg.RowCount := Sg.RowCount + 1;

For i := Sg.RowCount - 2 downto 1 do

Sg.Rows[i + 1] := Sg.Rows[i];

Sg.Cells[0, 1] := Head^.Data;

Sg.Cells[1, 1] := Head^.Name;

Sg.Cells[2, 1] := Head^.Author;

Sg.Cells[3, 1] := inttostr(Head.Price);

Sg.Cells[4, 1] := Head^.Note;

ShowMessage('CD/DVD диск добавлен.');

Exit;

end;

end;

// если список существует и добавляем музыку

if CmbDiskType.ItemIndex = 1 then

begin

// j - счётчик строки, в которую будем добавлять новый элемент(диск) списка

j := 1;

// если первый элемент(диск) в списке относится к типу фильмов

if Head^.Data = 'фильмы' then

begin

// пока следующий элемент(диск) списка существует

while H^.Next <> nil do

begin

{ если у следующего диска его тип относится к фильмам,

то переходим к следующему диску, увеличивая счётчик на 1 }

if H^.Next^.Data = 'фильмы' then

begin

H := H^.Next;

j := j + 1;

end

else

{ если у следующего диска его тип не относится к фильмам,

то увеличиваем счётчик на 1 и выходим из цикла }

begin

j := j + 1;

break;

end;

end;

// если дошли до последнего элемента(диска) списка, то увеличиваем счётчик на 1

if H^.Next = nil then

j := j + 1;

// добавляем элемент(диск) в список

Temp := H^.Next;

New(H^.Next);

with H^.Next^ do

begin

Data := 'музыка';

Name := EdtName.Text;

Author := EdtAuthor.Text;

Price := strtoint(EdtPrice.Text);

Note := EdtNote.Text;

Next := Temp;

end;

end

else

// если первый элемент(диск) в списке не относится к типу фильмов

begin

// добавляем в список новый элемент(диск) как первый элемент списка

New(H);

H^.Data := 'музыка';

H^.Name := EdtName.Text;

H^.Author := EdtAuthor.Text;

H^.Price := strtoint(EdtPrice.Text);

H^.Note := EdtNote.Text;

H^.Next := Head;

Head := H;

end;

with FrmMain do

begin

{ если активирована сортировка по наименованию, сортируем

соответствующим образом и выводим на экран список }

if Rg.ItemIndex = 0 then

begin

Sort(0);

ShowMessage('CD/DVD диск добавлен.');

Exit;

end;

{ если активирована сортировка по автору, сортируем

соответствующим образом и выводим на экран список }

if Rg.ItemIndex = 1 then

begin

Sort(1);

ShowMessage('CD/DVD диск добавлен.');

Exit;

end;

{ если никакая сортировка не активирована,

вставляем в таблицу добавленный элемент(диск) }

Sg.RowCount := Sg.RowCount + 1;

For i := Sg.RowCount - 2 downto j do

Sg.Rows[i + 1] := Sg.Rows[i];

Sg.Cells[0, j] := 'музыка';

Sg.Cells[1, j] := EdtName.Text;

Sg.Cells[2, j] := EdtAuthor.Text;

Sg.Cells[3, j] := EdtPrice.Text;

Sg.Cells[4, j] := EdtNote.Text;

ShowMessage('CD/DVD диск добавлен.');

Exit;

end;

end;

// если список существует и добавляем софт

if CmbDiskType.ItemIndex = 2 then

begin

// j - счётчик строки, в которую будем добавлять новый элемент(диск) списка

j := 1;

// если первый элемент(диск) в списке не относится к типу софт

if Head^.Data <> 'софт' then

begin

// пока следующий элемент(диск) списка существует

while H^.Next <> nil do

begin

{ если у следующего диска его тип не относится к софту,

то переходим к следующему диску, увеличивая счётчик на 1 }

if H^.Next^.Data <> 'софт' then

begin

H := H^.Next;

j := j + 1;

end

else

{ если у следующего диска его тип относится к софту,

то увеличиваем счётчик на 1 и выходим из цикла }

begin

j := j + 1;

break;

end;

end;

// если дошли до последнего элемента(диска) списка, то увеличиваем счётчик на 1

if H^.Next = nil then

j := j + 1;

// добавляем элемент(диск) в список

Temp := H^.Next;

New(H^.Next);

with H^.Next^ do

begin

Data := 'софт';

Name := EdtName.Text;

Author := EdtAuthor.Text;

Price := strtoint(EdtPrice.Text);

Note := EdtNote.Text;

Next := Temp;

end;

end

else

// если первый элемент(диск) в списке относится к типу софт

begin

New(H);

H^.Data := 'софт';

H^.Name := EdtName.Text;

H^.Author := EdtAuthor.Text;

H^.Price := strtoint(EdtPrice.Text);

H^.Note := EdtNote.Text;

H^.Next := Head;

Head := H;

end;

with FrmMain do

begin

{ если активирована сортировка по наименованию, сортируем

соответствующим образом и выводим на экран список }

if Rg.ItemIndex = 0 then

begin

Sort(0);

ShowMessage('CD/DVD диск добавлен.');

Exit;

end;

{ если активирована сортировка по автору, сортируем