- •1.1. Основные этапы создания программы
- •1.2. Алгоритмы
- •2.1. Структура типов в Turbo Pascal
- •Стандартные скалярные типы. Типы целых чисел
- •2.3. Операции побитовой обработки
- •2.4. Представление вещественных чисел в эвм
- •2.5. Символьный тип
- •2.6. Булевский тип
- •2.7. Перечисленный тип
- •2.8. Интервальный тип (диапазон)
- •3.1. Структура программы на turbo pascal
- •3.2. Основные операторы языка
- •3.2.1. Простые операторы
- •3.2.2. Операторы ввода-вывода
- •3.2.3. Структурные операторы
- •3.2.4. Условные операторы
- •3.2.5. Операторы повтора (цикла)
- •4.1. Массивы
- •4.2. Строковый тип
- •4.3. Множества
- •5.1. Процедуры и функции
- •5.2. Процедуры и функции пользователя
- •5.3. Передача параметров по значению и по ссылке
- •5.4. Рекурсивные процедуры и функции
- •6.1. Структура модулей
- •6.2. Компиляция и использование модулей
- •7.1. Записи
- •7.2. Вложенные записи
- •7.3. Записи с вариантами (вариантные записи)
- •7.4. Файлы
- •7.5. Подпрограммы для работы с файлами
- •7.5.1. Процедуры
- •7.5.2. Функции
- •7.6. Примеры программ для обработки файлов
- •7.7. Текстовые файлы
- •8.1. Структура оперативной памяти для программ на Turbo Pascal
- •8.2. Динамические структуры данных
- •8.3. Основные процедуры и функции для работы с динамическими переменными
- •8.4. Динамика выделения памяти в куче
- •8.5. Линейные списки. Способы создания и обработки
- •8.6. Нелинейные списки. Способы создания и обработки
- •Библиографический список
- •Оглавление
- •394026 Воронеж, Московский просп., 14
8.5. Линейные списки. Способы создания и обработки
Последовательное распределение – список членов последовательности, расположенных по порядку в последовательных ячейках памяти. Основными преимуществами последовательного распределения являются:
- легкость реализации и небольшой расход памяти;
- простая связь между номером элемента и адресом ячейки , в которой этот элемент хранится , где – адрес ячейки, где хранится первый элемент, – количество байт, требуемых для хранения одного элемента данного типа;
152
- возможность представления многомерных массивов.
Однако при последовательном распределении сложно реализовать операции включения новых и исключения имеющихся элементов.
Связанное распределение – это такой тип организации последовательности, при котором каждому элементу последовательности ставится в соответствие указатель , отмечающий ячейку, в которую записан элемент последовательности . Существует также указатель , который указывает на начальную ячейку последовательности:
При выборе последовательного или связанного представления сначала нужно проанализировать типы операций, которые будут выполняться над последовательностью. Если операции производятся над
случайными элементами, осуществляют поиск специфических элементов или производят упорядочивание элементов, то обычно лучше использовать последовательное распределение. Связанное распределение предпочтительнее, если в значительной степени используются операции включения или (и) исключения элементов, а также операции сцепления или (и) разбиения последовательностей.
Разновидности связанных списков. Если элемент указывает на , то такой список называется циклическим.
153
Tакой способ задания списка позволяет достигнуть любой элемент из любого другого элемента последовательности. Включение и исключение здесь осуществляется так же, как и в нециклических списках, а сцепление и разбиение реализуются сложнее.
Стек – последовательность, у которой все включения и выключения элементов происходят только в ее левом конце, называемом вершиной стека. Стек работает по правилу: “Первый пришел – последний ушел”.
Работа со стеком.
type ukaz = ^stack;
stack = record
inf: integer;
next: ukaz
end;
var top, kon, newel: ukaz; value: integer;
procedure sozd; {Помещение элементов в стек}
begin
top: = nil;
while true do
begin
read (value);
If value = 9999 then exit;
new(kon); {Выделение памяти для}
{хранения текущего элемента}
{Заполнение информационного поля}
kon^ . inf: = value; }
{В поле ссылки каждого элемента }
{помещаем адрес элемента, за которым}
{он следует; для элемента, вводимого}
{первым, этот адрес будет равным nil}
kon^ . next: = top;
154
{Запоминаем текущую вершину стека}
top: = kon;
end; {while}
end; {конец процедуры sozd}
procedure dob; {Добавляет новые элементы}
{в уже существующий стек,}
{адрес вершины которого }
{должен быть известен}
begin
while true do
begin
read (value);
if (value = 9999) then exit;
new (newel);
newel^ . next: = top;
newel^ . inf: = value;
top: = newel;
end;
end;
procedure udal; {Удаляется один элемент из}
{стека; указатель вершины}
{стека перемещается к}
{следующему элементу}
begin
top:= top^.next;
end;
procedure writ; {Вывод элементов стека}
{на экран}
begin
kon:=top;
while kon<> nil do
begin
writeln(kon^ . inf);
155
kon: = kon^ . next;
end;
end;
bеgin {Головная программа}
sozd;
writ;
dob;
writ;
udal;
writ;
end.
Вот как будет выглядеть стек, в который записаны последовательно числа 3, 15, 7:
– адреса, по которым элементы стека размещены в динамической области памяти. Адрес вершины стека хранится в переменной .
Рассмотрим механизм удаления из стека элемента, находящегося в любом месте стека. Допустим, что надо удалить элемент со значением .
Алгоритм удаления элемента применительно к рассмотренной схеме стека, состоит из следующих шагов:
156
- определение адреса удаляемого элемента ();
- сохранение адреса элемента, предшествующего удаляемому ();
- замена поля ссылки элемента, предшествующему удаляемому элементу, на поле ссылки удаляемого элемента ().
Однако этот алгоритм не будет работать в том случае, если необходимо удалять группы одинаковых элементов, находящихся в любой части стека.
В этом случае после определения адреса удаляемого элемента необходимо провести дополнительный анализ:
- если удаляемый элемент является вершиной стека, то вершина стека должна переноситься на следующий элемент до тех пор, пока вершиной стека не станет элемент, отличающийся от удаляемого, то есть, до тех пор, пока не будет удалена вся группа одинаковых элементов;
- если группа удаляемых элементов будет находиться не
в начале стека, то необходимо обеспечить сохранность адреса элемента, предшествующего группе удаляемых элементов до тех пор, пока эта группа не будет полностью удалена.
Далее приведен текст программы, реализующей алгоритм удаления заданного элемента из стека.
type
ukaz=^stek;
stek=record
inf: integer;
next:ukaz;
end;
var
v,w,flag,flag1:integer;
kon,top,t1,t:ukaz;
begin {Создание стека}
157
top:=nil;
while true do
begin
writeln('Введите очередной член ряда');
readln(v);
if(v=9999) then break;
new(kon);
kon^.inf: = v;
kon^.next: = top;
top:=kon;
end;
{Вывод элементов стека на экран}
kon:=top;
while kon<> nil do
begin
write(kon^.inf,' ');
kon:=kon^.next;
end;
kon: = top; flag: = 0; t1: = top; t: = kon; flag1: = 0;
writeln('Введите значение удаляемого элемента');
readln(w);
while kon<>nil do
begin
if(kon^.inf=w) then
{Удаление группы одинаковых элементов из начала}
{стека}
begin
if (flag=0) then
begin
t1:=kon^.next;
kon:=t1;
end
else
158
{Удаление группы одинаковых элементов из}
{середины и конца стека}
begin
if (flag1=0) then
begin
t^.next: = kon^.next;
kon:=kon^.next;
flag:=1;
end
else begin
t^.next:=kon^.next;
t:=kon;
kon:=kon^.next;
flag:=1;
flag1:=1;
end;
end;
end
else
begin
t:=kon;
kon:=kon^.next;
flag:=1;
end;
end;
{Вывод на экран результирующего стека}
kon:= t1;
while kon<> nil do
begin
write(kon^.inf,' ');
kon:=kon^.next;
end;
end.
159
Очередь - это последовательность, в которой все включения элементов производятся на правом конце списка (в конце очереди), а исключения производятся на левом конце (в начале очереди). Очередь работает в режиме “Первый пришел – первый ушел”. Поэтому при работе с очередью необходимо хранить как адрес первого элемента очереди, так и адрес последнего (right, left).
Механизм формирования очереди (3, 15, 7) можно по шагам представить так:
1.
2.
3
type
ukaz = ^stack;
stack = record
inf: integer;
next: ukaz
end;
var pp, kon, newel, right, left: ukaz; value: integer;
160
procedure sozd; {Организация очереди}
begin
read (value);
if (value =9999) then exit;
new(kon); kon^.next: = nil;
kon^.inf: = value;
right: = kon;
left: = kon;
while true do
begin
read (value);
if value = 9999 then exit;
new(kon); kon^ . next: = left;
kon^ . inf: = value; left: = kon;
end;
end;
{Добавление новых элементов в уже существующую очередь.} {Добавление происходит справа}
procedure dob;
begin
while true do
begin
read (value);
If value = 9999 then exit;
new (newel);
right^.next: = newel;
newel^ . next: = nil;
newel^ . inf: = value;
right = newel;
end;
end;
{Удаление элемента из очереди, удаление происходит слева}
161
procedure udal;
begin
left: = left^.next:
end;
{Вывод на экран элементов очереди}
procedure writ;
begin
pp: = top;
while pp <> nil do
begin
writeln(pp^ . inf);
pp: = pp^ . next;
end;
end;
bеgin
sozd; dob; udal; writ;
end.
Двусвязный список. Если каждый элемент списка имеет два связанных с ним указателя: на предыдущий и последующий элемент и , то такой список называется дважды связанным или двусвязным. В таком списке для
любого элемента есть свободный доступ к предыдущему и последующему элементам. Двусвязный список можно сделать циклическим.
Структура двусвязного списка циклического может быть представлена так:
162
type ukaz = ^Stack;
stack = record
inf: integer;
{Левое и правое поля ссылок}
nextRight, nextLeft: ukaz;
end;
var point, kon, nt, newel, right, left: ukaz;
value: integer;
procedure sozd; {Организация двусвязной очереди}
begin {Запись первого элемента в очередь}
read (value);
if (value =9999) then exit;
new(kon);
kon^ . inf:=value;
kon^.nextRight: = nil;
kon^.nextLeft: = nil;
right: = kon;
nt: = kon;
{Запись элементов в очередь, начиная со }
{второго}
while true do
begin
read (value);
if value = 9999 then exit;
new(kon);
kon^ . inf:= value;
kon^ . nextRight: = nt;
nt^. nextLeft: = kon;
end;
nt^ .nextLeft: = nil;
left: = nt;
end;
{Добавление нового элемента в двусвязный}
163
{список. Новый элемент добавляется в}
{список после элемента, на который}
{указывает значение point}
procedure dob;
begin
read (value);
if value = 9999 then exit;
new (newel);
newel^ . inf: = value;
newel^ . nextRight: = point^. nextRight;
newel^ . nextLeft = point;
point^. nextRight ^. nextLeft: = newel;
point^. nextRight: = newel;
end;
{Удаление элемента из двусвязной очереди.}
{Из списка удаляется элемент, следующий}
{ за элементом, на который указывает}
{значение point}
procedure udal;
begin
point^. nextRight:=point^. nextRight^ . nextRight;
point^. nextRight^ .nextLeft: = point;
end; bеgin
sozd;
dob;
udal;
end.