Бабалова Алгоритмизация задач и структурирование программ 2013
.pdfStack – название стека, PStack – указатель на стек, Item – элемент стека и Next – указатель на следующий элемент стека.
Двусвязный список: Type
PLine=^Line;
Line=record
Item:PString;
Prev,Next:PLine;
end;
Line – название очереди, PLine – указатель на очередь, Item – элемент очереди, Prev – указатель на предыдущий элемент очереди, Next – указатель на следующий элемент очереди.
Кольцевой список представляет собой список, конец которого замкнут на начало. Указатель последнего элемента списка должен ссылаться на начало списка. Формирование списка – это, прежде всего, выделение памяти из кучи (Heap) для записи списочных элементов. Стандартные процедуры для работы со списочными структурами: New(List) → выделение адреса в куче для элемента списка. Dispose(List) → уничтожение адреса одного элемента списка.
Пример 5.1. Создать список сотрудников некоторой организации и найти среди них однофамильцев.
Решение задачи начинается с создания списков сотрудников. Исходные данные сохраним в файле. Для поиска однофамильцев выполним сортировку списочной структуры данных и найдем всех однофамильцев. На рис. 28 приведена структура программы. Все виды работ предлагается перечислить в меню. Создание списка возможно только тогда, когда сформирован файл с требуемыми данными. Поиск однофамильцев осуществляется только после сортировки созданного списка данных. Все действия, обозначенные в меню, оформляются процедурами или функциями.
В структуре программы есть метод «Создание списка». На рис. 29 изображен использованный в примере решения этой задачи алгоритм создания односвязного списка типа очереди.
Алгоритм поиска однофамильцев Seach_double разработан для отсортированного списка. В этом случае поиск одинаковых записей существенно упрощается. Алгоритм поиска однофамильцев приведен на рис. 30.
71
Рис. 28. Структура программы для обработки списков
Рис. 29. Алгоритм создания списка типа очереди
72
Рис. 30. Алгоритм поиска однофамильцев в списке
Валгоритме поиска есть два цикла для движения по списку. Внутренний цикл собственно выявляет однофамильцев. А внешний цикл обеспечивает движение по списку для выбора следующей фамилии. Логическая переменная v контролирует выбор однофамильца. Переменная i определяет количество найденных однофамильцев. Процедура, описывающая этот алгоритм, имеет в программе аналогичное имя.
Валгоритме выделены два важных момента – это сохранение начала списка в переменной lb и обозначение конца списка – переменная lk.
Программа: program ProjectList_rec; {$APPTYPE CONSOLE} uses
SysUtils,Windows; //Для работы со строками пришлось добавить
// модуль среды Windows, содержащий методы обработки строк.
73
const a:array[1..6]of string[30]=( '1.Создать файл', '2. Создать список ', '3. Вывод списка ',
'4. Сортировать список', '5. Найти однофамильцев ', '6. Выход') ;
Type str=string[30]; D_d=record
Title:str;
Fnm,Secnm:str;
Number:word;
end;
//Структура данных представлена как запись
//из полей фамилии, имени, отчества и
//некоторого номера сотрудника
ff=file of D_d;
//Типизированный файл из записей
Plist=^List;
List=record
lis:D_d; // Информационное поле списка next:Plist;
end; // Списочная структура данных var n,i:integer;
ch:char;
f1:ff;
pn,Pstart:Plist;
// Необходимые глобальные переменные function ToRus(winStr:String):string; begin
setlength(Result,Length(WinStr));
CharToOEM(PChar(WinStr),PChar(Result));
end;
//Эта функция нужна только для консольного
//приложения. Вы ее просто копируете в
//каждую новую свою программу, если
//хотите видеть комментарии на русском языке. procedure save_data_file(var f:ff);
74
// Процедура для сохранения данных в файле var ld:d_d;
begin
writeln(ToRus('******Введите исходные данные')); repeat
with ld do begin
write(ToRus('Фамилия ')); readln(Title); write(ToRus('Имя ')); readln(Fnm); write(ToRus('Отчество ')); readln(Secnm); write(ToRus('Номер ')); readln(number);
end;
write(f,ld); writeln(ToRus('******Есть еще сведения? '));
readln(ch); until ch ='n'; closefile(f);
writeln(ToRus('******Данные сохранены в файле*** ')); readln;
end;
procedure Insert_list(Var pp:pList;el:D_d); // Процедура для вставки элемента в список
Var ls,lp: pList; begin
if pp=nil then begin new(lp);
with lp^ do begin lis:=el; next:=nil; end; pp:=lp;
// Запоминаем начало списка
75
end else begin
new(ls);
lp^.next:=ls; with ls^ do
begin lis:=el; next:=nil;
end;
lp:=ls;
// Обеспечиваем движение по списку end;
end;
procedure List_Create(var pp:plist);
// Процедура создания списка из данных, сохраненных в файле var d:D_d;
begin
While not eof(f1) do begin
read(f1,d); Insert_list(pp,d); end;
closefile(f1);
end;
//Вывод созданного списка procedure List_Output(var pp:plist);
var lp:plist; i:integer;
begin lp:=pp; i:=1;
while lp<>nil do begin
write(i, '---'); with lp^ do
begin write(lis.Title,' + '); write(lis.Fnm,' + ');
76
write(lis.secnm,' + '); writeln(lis.number);
end;
lp:=lp^.next;
i:=i+1;
end;
end;
procedure Sort_list(var pp:Plist); // Сортировка списка по фамилиям
var p1,p2:plist; tt:D_d; nowswap:boolean;
begin Repeat
p1:=pp;
p2:=p1^.next;
nowswap:=true; while(p2<>nil) do
begin
if (p1^.lis.Title>p2^.lis.Title) then begin
nowswap:=false; tt:= p1^.lis; p1^.lis:= p2^.lis; p2^.lis:=tt;
//Для сортировки списка достаточно
//переставить только поля данных
end;
p1:=p2;
p2:=p2^.next;
end;
Until nowswap; end;
procedure Seach_double(var pp:Plist); // Процедура поиска однофамильцев
var i:integer; v:boolean;
77
lp,ls:plist; begin
lp:=pp;
ls:=lp;
i:=1;
while lp<> nil do begin
v:=true ;
while (v and(ls<>nil)) do begin
if ls<>lp then
if lp^.lis.Title =ls^.lis.Title then begin
write(i,' '); write(lp^.lis.Title+' '); write(lp^.lis.Fnm +' '); write(lp^.lis.Secnm +' '); write(lp^.lis.number); writeln;
i:=i+1;
v:=false;
end;
ls:= ls^.next; end;
ls:=lp;
lp:=lp^.next;
end;
If i=1 Then
writeln (ToRus('*****Однофамильцев нет****'));
end;
begin // Основная программа с меню работ writeln(ToRus('*****начало работы****'));
Assignfile(f1,'Wind.dat');
pn:=nil;
For i:=1 to 6 do writeln(ToRus(a[i]):40);
// Вывод на экран меню
78
Repeat
writeln(ToRus('*****Введите номер выполняемого дейст-
вия****'));
readln(n); case n of
1: begin
writeln(ToRus('*****Файл надо создать****'));
rewrite(f1); save_data_file(f1); end;
2: begin Pstart:=Init(pn); reset(f1);
Writeln(ToRus('*****Создание списка****' )); list_create(Pstart);
end; 3: begin
writeln (ToRus('*****Вывод списка****'));
List_Output(Pstart);
end; 4: begin
writeln (ToRus('*****Сортировка списка****'));
Sort_list(Pstart); List_Output(Pstart); readln;
end; 5: begin
writeln (ToRus('*****Поиск однофамильцев****'));
Seach_double(PStart); readln;
end; 6: Halt; end;
Until false;
{ TODO -oUser -cConsole Main : Insert code here }
end.
79
Экран с решением задачи показан на рис. 31.
Рис. 31. Решение задачи по поиску однофамильцев
Виллюстрации решения задачи отражены все действия со списком: создание списка, сортировка списка по алфавиту и поиск однофамильцев в созданном списке.
Рассмотрим решение задачи со списочной структурой с использованием визуальных компонент среды Delphi.
Пример 5.2. Игроки имеют свои номера. Выпадает случайное число. Это число определяет игрока, который выбывает из игры. Побеждает тот игрок, номер которого не будет назван.
Врешении задачи надо будет удалять выпавший номер игрока из списка. На рис. 31 изображен алгоритм удаления элемента из списка.
80