Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Мансуров. Основы программирования в среде Lazarus. 2010

.pdf
Скачиваний:
68
Добавлен:
27.04.2021
Размер:
6.3 Mб
Скачать

Глава 4 Типовые алгоритмы обработки информации

____________________________________________________________________

view_MyList (pHead);

writeln;

end;

end; { end of case }

until choose = 5;

writeln(UTF8ToConsole('Нажмите любую клавишу'));

readkey;

end.

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

ние элементов производится только в начале или в конце списка. Какие это списки:

линейный список, в котором добавление или удаление элементов про-

изводится только в одном конце. Читатель, наверное, уже догадался, что это есть не что иное, как стек!

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

ном конце, а удаление на противоположном конце списка. Если внима-

тельно подумать, то работа такого списка будет напоминать живую оче-

редь людей в магазине. Поэтому такой список так и называют – очередь.

Часто очередь называют структурой FIFO (First In - First Out, т.е. "первый пришел, первый ушел").

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

Реализуем рассмотренные динамические структуры с помощью линейных списков.

371

4.3 Динамические структуры данных

____________________________________________________________________

4.3.6 Реализация динамических структур линейными списками

4.3.6.1. Реализация стека

Для того чтобы поместить элемент в стек, достаточно написать следующий

код:

New(p); // Резервируем память для нового элемента p ^.data:= ELEM; //Записываем данные

p^.next:= CTEK;// устанавливаем ссылку на текущую вершину стека

CTEK:= p; // Теперь новый элемент стал верхушкой стека Для того чтобы взять элемент из верхушки стека, необходим код:

if CTEK <> nil then // Если стек не пуст begin

ELEM:= CTEK^.data; // Взять элемент

p:= CTEK^.next; // Указатель на следующий элемент

Dispose(CTEK);// Удалить текущий элемент из вершины стека

CTEK:= p; //Предыдущий элемент сделать вершиной стека

Приведем полный листинг программы работы со стеком:

program stack; {$mode objfpc}{$H+} uses

CRT, FileUtil; type

c = ^ MyStack; // указатель

MyStack = record // структура записи data: integer; // содержательная часть стека

372

Глава 4 Типовые алгоритмы обработки информации

____________________________________________________________________

next: c; // ссылка на следующий элемент end;

var

choose: integer; EMPTY: boolean;

CTEK: c; // указатель, указывает на вершину стека ukaz: c; // рабочий указатель

ELEM: integer; // содержательный элемент стека

{================================================ } procedure Put_Stack(var ELEM: integer; var CTEK: c);

{================================================ }

begin

New(ukaz); // создаем новый элемент стека

ukaz^.data:= ELEM; // В поле data записи записываем значение ukaz^.next:= CTEK; // ссылка на следующий элемент

CTEK:= ukaz; // вершиной стека становится новый элемент end;

{ ================================================ } procedure Take_Stack(var ELEM: integer; var CTEK: c;

var EMPTY:Boolean);

{ ================================================ } var ukaz: c;

begin

if CTEK <> nil then begin

ELEM:= CTEK^.data; // Берем элемент из вершины стека ukaz:= CTEK^.next; // Указатель на следующий элемент

Dispose(CTEK); // уничтожение текущей вершины

373

4.3 Динамические структуры данных

____________________________________________________________________

CTEK:= ukaz; // вершиной стека становится следующий элемент

end

else EMPTY:= true;

end;

procedure View_Stack(var CTEK: c);

var ukaz: c;

begin

writeln(UTF8ToConsole('Содержимое стека')); ukaz:= CTEK; // Берем вершину стека

{В цикле проходим все элементы стека и печатаем их} while ukaz <> nil do

begin

write(ukaz^.data, ' '); ukaz:= ukaz^.next;

end;

writeln;

end;

begin

{Инициализация стека}

CTEK:= nil;

repeat

EMPTY:= false;

writeln(UTF8ToConsole('Выберите нужный режим работы :'));

writeln(UTF8ToConsole('Поместить элемент в стек

1'));

writeln(UTF8ToConsole('Взять элемент из стека

2'));

writeln(UTF8ToConsole('Просмотреть содержимое стека 3'));

writeln(UTF8ToConsole('Выход из программы

4'));

readln(choose);

 

374

Глава 4 Типовые алгоритмы обработки информации

____________________________________________________________________

case choose of 1: begin

writeln(UTF8ToConsole('Введите новый элемент стека')); readln(ELEM);

Put_Stack(ELEM, CTEK); end;

2: begin

Take_Stack(ELEM, CTEK, EMPTY); if EMPTY then

begin

writeln(UTF8ToConsole('Стек пуст'));

end

else

begin

writeln(UTF8ToConsole('Из стека взят элемент '),

ELEM);

end;

end; 3: begin

View_Stack(CTEK); end;

end; { end of case } until choose = 4;

end.

4.3.6.2. Реализация очереди с помощью линейного списка

Проще всего для этого завести два указателя. Указатель на первый элемент очереди first и указатель на последний элемент очереди last. Листинг про-

граммы:

375

4.3 Динамические структуры данных

____________________________________________________________________

program queue; // queue означает по английски очередь

{$mode objfpc}{$H+} uses

CRT, FileUtil; type

PQueue = ^Element; // указатель

Element = record // структура записи

data : integer; // содержательная часть очереди next : PQueue; // ссылка на следующий элемент end;

TQueue = record // структура для реализации очереди

first: PQueue; // указатель, указывает на первый элемент очереди last: PQueue; // указатель, указывает на последний элемент очереди end;

{============================================= } procedure Put_Que(ELEM: integer; var Que: TQueue);

{============================================= }

var ukaz: PQueue; // временный указатель

begin

if (Que.last = nil) then

{Если очередь пуста, то указатели на первый и последний элемент будут совпадать}

begin

{Выделяем память для нового элемента}

Que.last:= New(PQueue);

Que.first:= Que.last; // Приравниваем указатели

Que.last^.data:= ELEM; // записываем данные

376

Глава 4 Типовые алгоритмы обработки информации

____________________________________________________________________

Que.last^.next:= nil; // Следующий элемент пока пустой end

else begin

ukaz:= New(PQueue); ukaz^.data:= ELEM; ukaz^.next:= nil;

Que.last^.next:= ukaz; // ссылка на следующий элемент

Que.last:= ukaz; // Сдвигаем указатель на последний элемент end;

end;

{ ================================================== } procedure Take_Que(var ELEM: integer; var Que: TQueue;

var EMPTY:Boolean);

{ ================================================== }

var ukaz: PQueue; begin

if (Que.first = nil) then begin

EMPTY:= true; end

else begin

ELEM:= Que.first^.data; {Первый элемент очереди} ukaz:= Que.first; // Запомним ссылку

Que.first:= Que.first^.next; {переход на следующий элемент}

377

4.3 Динамические структуры данных

____________________________________________________________________

Dispose(ukaz); {уничтожение текущего элемента} end;

end;

{================================ } procedure View_Que(var Que: TQueue);

{================================ }

var

ukaz: PQueue; begin

writeln(UTF8ToConsole('Содержимое очереди')); ukaz:= Que.first; // Берем первый элемент очереди

{В цикле проходим все элементы очереди и печатаем их} while ukaz <> nil do

begin

write(ukaz^.data, ' '); ukaz:= ukaz^.next;

end;

writeln;

end;

var

choose: integer; EMPTY: boolean; Que: TQueue;

ELEM: integer; // содержательный элемент очереди begin

{Инициализация очереди}

378

Глава 4 Типовые алгоритмы обработки информации

____________________________________________________________________

Que.last:= nil;

repeat

EMPTY:= false;

writeln(UTF8ToConsole('Выберите нужный режим работы :')); writeln(UTF8ToConsole('Поместить элемент в очередь 1'));

writeln(UTF8ToConsole('Взять элемент из очереди 2'));

writeln(UTF8ToConsole('Просмотреть содержимое очереди 3'));

writeln(UTF8ToConsole('Выход из программы

4'));

readln(choose);

 

case choose of

 

1: begin

 

writeln(UTF8ToConsole('Введите новый элемент')); readln(ELEM);

Put_Que(ELEM, Que); end;

2: begin

Take_Que(ELEM, Que, EMPTY); if EMPTY then

begin

writeln(UTF8ToConsole('Очередь пуста'));

end

else

begin

writeln(UTF8ToConsole('Из очереди взят элемент '),

ELEM);

end;

end; 3: begin

View_Que(Que);

379

4.3 Динамические структуры данных

____________________________________________________________________

end;

end; { end of case }

until choose = 4;

end.

Реализация дека теперь для вас не представляет такой уж сложной задачей.

Попробуйте реализовать его самостоятельно.

4.3.6.3. Реализация двоичного дерева с помощью линейного списка

Двоичное дерево можно представить с помощью двухсвязного списка сле-

дующим образом:

type

 

PTree= ^Tree;

// Указатель на дерево

Tree= record

// Само дерево, имеет тип - запись

node: string;

// значение вершины (узла) дерева

left: PTree; // Ссылка на левое поддерево right: PTree; // Ссылка на правое поддерево end;

Здесь для разнообразия в качестве значений вершин мы взяли строки сим-

волов. Напишем рекурсивную процедуру поиска вершины по его значению:

procedure search_node(Elem: string;

ptr_tree: PTree;

var current_tree: PTree);

var

p: ^Tree; // рабочий указатель begin

380