
3 Логические структуры данных
Основная структура данных проекта – линейный двусвязный список. Атрибутами элементов списка являются имя, фамилия и отчество члена ВТК, год рождения, код ХД, сумма вознаграждения и горо, где находится отделение банка. Кроме того, каждый элемент списка содержит два указателя, один из которых, прямой указатель (direct pointer), адресует следующий справа элемент, а другой, обратный указатель (backward pointer), адресует предыдущий элемент списка.
Ниже представлено описание элемента списка.
Type
TPointer = ^TListStore;
TListStore=record
Name: string[50];//имя
FamilyName:string[50];//фамилия
Patronymic:string[50];//отчество
Year:integer;//год рождения
Kod:string[10];//код ХД
SummMany:extended;//вознаграждение
City:string[100];//город
Dir,Back:TPointer;//указатели
end;
Начало и конец такого списка эквивалентны, так как доступ к элементу может быть осуществлен с любого конца. Поэтому вместо терминов «начало» и «конец» списка используют термины «левый конец» и «правый конец». Соответственно называются и указатели:
Var
Left, Right, Current, G, Sort:TPointer;
Логическая структура списка:
Name
FamilyName
Patronymic
Year
Kod
SummMany
City
Dir
Back
4 Алгоритмы обработки основных структур
Вся работа со списком определена в классе TNoFreeXD. Ниже рассмотрены все его процедуры (операции над списком).
TNoFreeXD=class(TObject)
private
Left{начало}, Right{конец}, Current, G, Sort{для сортировки}:TPointer;
procedure ElementToStringGrid(i:Cardinal;StringGrid:TStringGrid);
public
procedure FormingList;
procedure GetList(StringGrid:TStringGrid);
procedure ClearList;
procedure Sorting(Index:Integer;Increase:Boolean);
procedure Replace;
procedure Search(Index:Integer;Text:String;StringGrid:TStringGrid);
end;
1. Формирование линейного двусвязного списка членов незавершенных ХД.
Производится просмотр всех членов ВТК. Если член ВТК связан с ХД который не завершен, то он заносится в список (заполняются соответствующие поля элемента списка).
procedure TNoFreeXD.FormingList;
var
i,j,k:Cardinal;
str,_strYear:string;
Year: Word;
Month: Word;
Day: Word;
begin
ClearList;
New(Current);
Left:=Current;//указатель на начало
Current^.Back:=nil;//указатель на предыдущий должен равен быть в начале (nil)
for i:=0 to GetBTKM-1 do
begin
for j:=0 to GetXDM-1 do
begin
DecodeDate(XD[j].DateCreat,Year,Month,Day);
_strYear:=IntToStr(Year);
str:=IntToStr(XD[j].Number)+'/'+_strYear[3]+_strYear[4];
if (str=BTK[i].Kod) and (XD[j].PriznakFree=false) then
begin
Current^.Name:=BTK[i].Name;
Current^.FamilyName:=BTK[i].FamilyName;
Current^.Patronymic:=BTK[i].Patronymic;
Current^.Year:=BTK[i].Year;
Current^.Kod:=BTK[i].Kod;
Current^.SummMany:=BTK[i].SummMany;
for k:=0 to GetBANKM-1 do
begin
if BANK[k].Number=BTK[k].NumberBank then
begin
Current^.City:=BANK[i].City;
end;
end;
New(Current^.Dir);
Current^.Dir^.Back:= Current;//указатель на данный элемент
Current:=Current^.Dir;//указатель на следующий
end;
end;
end;
Current^.Back^.Dir:=nil;
Right:=Current^.Back;//указатель на конец списка(равен предыдущему)
Dispose(Current);
end;
Логические схемы операции формирования списка.
После выполнения операторов
New(Current); Left:=Current; Current^.Back:=nil;
После нахождения первого члена ВТК.
После завершения просмотра.
После выполнения операторов
Current^.Back^.Dir:=nil; Right:=Current^.Back; Dispose(Current);
2. Просмотр списка и его отображение в таблице StringGrid.
Сначала производится очистка таблицы, а затем последовательный просмотр элементов списка, начиная с левого конца.
procedure TNoFreeXD.GetList(StringGrid:TStringGrid);
var
i,j:integer;
begin
for i:=1 to 25 do
for j:=0 to 8 do
StringGrid.Cells[j,i]:='';
Current:=Left;//получаем указатель на начало
i:=1;
while Current<> nil do
begin
StringGrid.Cells[0,i]:=IntToStr(i);
StringGrid.Cells[1,i]:=Current^.Name;
StringGrid.Cells[2,i]:=Current^.FamilyName;
StringGrid.Cells[3,i]:=Current^.Patronymic;
StringGrid.Cells[4,i]:=IntToStr(Current^.Year);
StringGrid.Cells[5,i]:=Current^.Kod;
StringGrid.Cells[6,i]:=FloatToStr(Current^.SummMany);
StringGrid.Cells[7,i]:=Current^.City;
Current:=Current^.Dir;//указатель на следующий элемент
Inc(i);
end;
end;
3. Поиск элементов по заданному атрибуту в списке
Пользователь задает атрибут поиска и его значение. В процедуре Search производится последовательный просмотр элементов списка в направлении от левого конца к правому. Если элемент удовлетворяет искомому значению, то он помещается в таблицу. По завершении поиска появляется сообщение о количестве найденных элементов.
Procedure TNoFreeXD.Search(Index:Integer;Text:String;StringGrid :TStringGrid);
var i, j:integer;
begin
for i:=1 to 250 do
for j:=0 to 5 do
StringGrid.Cells[j,i]:='';
Current:=Left;//получаем указатель на начало
i:=1;
while Current<> nil do
begin
case Index of
0: if Current^.Name=Text
then
begin
ElementToStringGrid(i,StringGrid);
Inc(i);
end;
1: if Current^.FamilyName=Text
then
begin
ElementToStringGrid(i,StringGrid);
Inc(i);
end;
2: if Current^.Patronymic=Text
then
begin
ElementToStringGrid(i,StringGrid);
Inc(i);
end;
3: if Current^.Year=StrToInt(Text)
then
begin
ElementToStringGrid(i,StringGrid);
Inc(i);
end;
4: if Current^.SummMany=StrToFloat(Text)
then
begin
ElementToStringGrid(i,StringGrid);
Inc(i);
end;
5: if Current^.City=Text
then
begin
ElementToStringGrid(i,StringGrid);
Inc(i);
end;
end;
Current:=Current^.Dir;
end;
MessageDlg('Поиск завершен. Найдено элементов - '+IntToStr(i-1),mtInformation,[mbOk],0);
end;
procedure TNoFreeXD.ElementToStringGrid(i:Cardinal;StringGrid :TStringGrid);
begin
StringGrid.Cells[0,i]:=IntToStr(i);
StringGrid.Cells[1,i]:=Current^.Name;
StringGrid.Cells[2,i]:=Current^.FamilyName;
StringGrid.Cells[3,i]:=Current^.Patronymic;
StringGrid.Cells[4,i]:=IntToStr(Current^.Year);
StringGrid.Cells[5,i]:=Current^.Kod;
StringGrid.Cells[6,i]:=FloatToStr(Current^.SummMany);
StringGrid.Cells[7,i]:=Current^.City;
end;
4. Сортировка списка прямым выбором
Пользователь выбирает способ упорядочения и атрибут сортировки списка.
Алгоритм этого метода сортировки следующий.
Выбирается (выделяется) элемент с наименьшим (или наибольшим – в зависимости от способа упорядочения: по возрастанию, по убыванию) значением атрибута сортировки. Затем этот элемент меняется местом с первым элементом списка. Среди остальных элементов списка (т.е. среди всех кроме первого) снова выбирается элемент с наименьшим значением атрибута сортировки. Он меняется местом со вторым элементом списка. Далее все повторяется, пока не останется один наибольший элемент списка.
procedure TNoFreeXD.Sorting(Index:Integer;Increase:Boolean);
var
XPointer:TPointer;
begin
if Left=Right then Exit;
XPointer:=Left;
while XPointer^.Dir<>nil do
begin
Sort:=XPointer;//берем указатель на элемен
XPointer:=XPointer^.Dir;//перемещаемм указатель на следующий
G:=Sort;//элемент с которым будем сравнивать
Current:=G^.Dir;//следующий элемент
while Current<>nil do//пока не пройдем весь список
begin
case Index of
0: if Increase=True//как сортировать(убыванию или увелечению)
then
begin
if G^.Name<Current^.Name
then G:=Current;
end
else if G^.Name>Current^.Name
then G:=Current;
1: if Increase=True
then
begin
if G^.FamilyName<Current^.FamilyName
then G:=Current;
end
else if G^.FamilyName>Current^.FamilyName
then G:=Current;
2: if Increase=True
then
begin
if G^.Patronymic<Current^.Patronymic
then G:=Current;
end
else if G^.Patronymic>Current^.Patronymic
then G:=Current;
3: if Increase=True
then
begin
if G^.SummMany<Current^.SummMany
then G:=Current;
end
else if G^.SummMany>Current^.SummMany
then G:=Current;
4: if Increase=True
then
begin
if G^.City<Current^.City
then G:=Current;
end
else if G^.City>Current^.City
then G:=Current;
5: if Increase=True
then
begin
if G^.Year<Current^.Year
then G:=Current;
end
else if G^.Year>Current^.Year
then G:=Current;
end;
Current:=Current^.Dir;//указываем на следующий элемент
end;
//если было изменение(одно из if сработало) то меняем указатели
if G<>Sort then Replace;
end;
end;
procedure TNoFreeXD.Replace;
begin
if G^.Dir<>nil
then G^.Dir^.Back:=Sort
else Right:=Sort;
if Sort^.Dir<>G
then
begin
Sort^.Dir^.Back:=G;
G^.Back^.Dir:=Sort;
end;
if Sort^.Back<>nil
then Sort^.Back^.Dir:=G
else Left:=G;
Current:=G^.Dir;
if Sort^.Dir=G
then G^.Dir:=Sort
else G^.Dir:=Sort^.Dir;
Sort^.Dir:=Current;
if G^.Back=Sort
then
begin
Current:=Sort^.Back;
Sort^.Back:=G;
G^.Back:=Current;
end
else
begin
Current:=G^.Back;
G^.Back:=Sort^.Back;
Sort^.Back:=Current;
end;
end;
Логические схемы операции сортировки
Рассмотрим один из шагов сортировки списка по возрастанию года рождения (первый шаг).
Стартовая структура (часть линейного двусвязного списка). Указатель G ссылается уже на элемент с минимальным значением атрибута. Требуется поменять местами первый элемент, на который указывает Sort, и элемент, на который указывает G.
После выполнения G^.Dir^.Back:=Sort
После выполнения Sort^.Dir^.Back:=G; G^.Back^.Dir:=Sort;
После выполнения Left:=G; Current:=G^.Dir;
После выполнения G^.Dir:=Sort^.Dir; Sort^.Dir:=Current;
После выполнения
Current:=G^.Back; G^.Back:=Sort^.Back; Sort^.Back:=Current;
Преобразование к более привычному виду двусвязного списка.