List:=p; { а текущий – первым }
end else begin
{ вставка в середине или в конце списка }
p^.mNext:=q^.mNext; { связываем текущий со следующим }
q^.mNext:=p; { связываем предыдущий с текущим }
end
end
end;
{ Распечатка списка }
procedure PrintList;
{--- взять из P_54_1 ---}
end;
var i: integer;
begin {--- Главная программа ---}
List:= nil; { инициализация}
{ Заполнение списка }
for i:=1 to 20 do AddToSortList(100+Random(100), 'Деточкин');
{ Распечатка списка }
PrintList;
Readln;
end.
Разумеется, что проверку этой программы я возлагаю на вас.
Поиск в сортированном списке
Создав функцию поиска номера в сортированном списке, поставим победную точку. Будем искать запись, для которой номер в следующей за ней записи больше искомого (если следующая запись существует). Это условие совпадает с условием поиска при вставке в сортированный список. Найдя такую запись и сравнив её номер с искомым, сформируем результат: если номер найден, возвращаем указатель на эту запись, а иначе – NIL. Все это относится к программе «P_54_4».
{ P_54_4 – Поиск данных в сортированном списке }
type PRec = ^TRec; { Тип указатель на запись }
TRec = record { Тип записи для базы данных }
mNumber : integer; { Номер авто }
mFam : string[31]; { Фамилия владельца }
mNext : PRec; { Указатель на следующую запись }
end;
var List : PRec; { Указатель на начало списка (голова) }
{ Размещение нового элемента в сортированном списке }
procedure AddToSortList(aNumber: integer; const aFam : string);
{--- взять из P_54_1 ---}
end;
{ Распечатка списка }
procedure PrintList;
{--- взять из P_54_1 ---}
end;
{ Поиск в сортированном списке }
function Find(aNumber: integer): PRec;
var p : PRec;
begin
p:= List; { Поиск начинаем с головы }
{ Двигаемся по списку, пока следующий элемент существует
и его номер не больше искомого }
while Assigned(p) and Assigned(p^.mNext) and (p^.mNext^.mNumber <= aNumber)
do p:=p^.mNext;
{ Если конец списка не достигнут и номер совпадает… }
if Assigned(p) and (p^.mNumber = aNumber)
then Find:= p { то успешно! }
else Find:= nil; { а иначе не нашли }
end;
var i, N : integer; P : PRec;
begin {--- Главная программа ---}
List:= nil;
for i:=1 to 20 do AddToSortList(100+Random(100), 'Фамилия, Имя');
PrintList; { Просмотр списка }
repeat { Цикл экспериментов по поиску в списке }
Write('Укажите номер авто = '); Readln(N);
if N>0 then begin
P:= Find(N);
if Assigned(P)
then Writeln(P^.mNumber, '':3, P^.mFam)
else Writeln ('Не найдено!');
end;
until N=0
end.
Итоги
• Указатель на любой тип данных можно объявлять раньше типа, на который он ссылается.
• Односвязный список – это простейшая динамическая структура, отводящая под данные столько памяти, сколько им требуется.
• Элементы списка – это записи, содержащие в числе прочих данных указатель на следующую запись в списке.
• Элементы списка помещают в кучу и связывают между собой внедренными в них указателями.
• Первый элемент доступен через голову списка (указатель в статической памяти программы). Остальные элементы доступны по цепочке указателей, встроенных в записи.
• Сортировку списка можно совместить с его вводом.
А слабо?
А) Напишите функцию для подсчета элементов списка; она должна принимать указатель на голову списка, а возвращать целое число.
Б) Начертите блок-схему вставки записи в сортированный список.
В) Напишите процедуру для удаления первого элемента списка. Или слабо?
Г) Напишите процедуру сортировки уже готового списка. Подсказка: последовательно извлекайте элементы из несортированного списка и вставляйте в сортированный (потребуется две головы для двух списков).
Задачи на темы предыдущих глав
Д) В задаче 53-Г была представлена модель «глупого» винчестера. «Умный» винчестер отличается организацией внутренней очереди и челночным движением головки, которая следует попеременно то от внутренней дорожки к внешней, то обратно, попутно выполняя все накопившиеся в очереди запросы. Направление движения переключается, когда в текущем направлении не остается запросов, поэтому головка редко достигает крайних дорожек.
Ваша программа должна подсчитать общее время обработки запросов «умным» контроллером для набора данных из входного файла, составленного по правилам для задачи 53-Г. Создайте несколько наборов таких данных и сравните время их обработки двумя типами контроллеров: «умным» и «глупым».
Подсказка: для организации внутренней очереди контроллера здесь можно применить массив чисел (счетчиков). Каждый счетчик будет хранить текущее количество запросов для своей дорожки. При постановке запроса в очередь счетчик наращивается, а при извлечении уменьшается.
Глава 55
Слова, слова, слова…
Односвязные списки подоспели как раз вовремя, – сейчас они поработают в необычном проекте.
Частотный анализ текста
Однажды разгорелся спор об известном романе «Тихий Дон», – некоторые литераторы усомнились в авторстве Михаила Шолохова. Их сомнения развеяли программисты, вычислившие частотные характеристики нескольких его произведений. Что это за характеристики такие?
Предположим, вы подсчитали, что слово «Паскаль» упомянуто в этой книге 150 раз, а всего в книге 10000 слов. Тогда относительная частота слова «Паскаль» в книге составит 150 / 10000 = 0,015 или 1,5%. Если найти частоту употребления других слов книги, и расположить эти результаты в некотором порядке, то получится картина, подобная отпечатку пальца. У разных авторов эти «отпечатки» разные, зато у одного автора в разных произведениях – очень похожи! Обработав таким частотным анализатором несколько книг Михаила Шолохова, специалисты сравнили результаты и обнаружили на романе «Тихий Дон» «пальчики» донского писателя.
Слово за слово
Итак, мы беремся за разработку слегка упрощенного частотного анализатора. Это опять тот случай, где заранее неизвестен объём обрабатываемых данных. В самом деле, определить приблизительное количество слов в тексте не так уж сложно: посчитаем их на одной странице и умножим на число страниц. Но сколько из этих слов несовпадающих, разных? Не слышу ответа!
Наша программа будет читать не романы, а текстовые файлы, – возьмем файл какой-либо из наших программ, и посчитаем в нём слова, составленные из латинских букв. Для упрощения программы русские слова считать не будем, и пропустим слова, состоящие из одной буквы. Зато примем в расчет слова с цифрами и знаками подчеркивания, например, такие.
Begin, NIL, P1, q2, Words_Count, _1_
Нам предстоит выудить из текста подходящие слова, перевести их в верхний регистр, отсортировать по алфавиту и пересчитать.
Структура записи