Кроме односвязных списков, можно строить также и двусвязные. В такой структуре данных каждый элемент имеет указатели на оба соседних. То есть в описании типа элемента добавляется еще одно поле. Например, описание может выглядеть следующим образом:

Type

list=^element;

element=record

inf:string[20];

ukl, ukr:list

end;

У первого элемента указатель ukl будет равен nil, а у последнего элемента значение nil будет иметь указатель ukr.

Эту структуру даны можно применить, например, к решению задачи «Считалка-маятник».

Стеки и очереди

Стек и очередь являются структурами данных, широко применяемыми в стандартных алгоритмах, а также для построения моделей. Эти структуры также как списки являются линейными и определения типов данных для них также совпадают с теми, что применяются для односвязных списков.

Стек или магазин – линейная структура данных, имеющая одно «окно», применяемое для включения в него данных или «вталкивания» и для извлечения данных или «выталкивания». Устройство стека похоже на устройство патронного магазина для пистолета или автомата. Патроны (данные) вталкиваются в магазин при его снаряжении и выталкиваются при перезарядке оружия. При этом первым извлекается патрон, который был вставлен в магазин последним. Таким образом, стек или магазин представляет собой такую структуру, в которой для данных применяется правило «Последний вошел – первый вышел». По-английски это же будет звучать «Last In – Fist Out» или LIFO.

В отличие от стека, очередь следует понимать в обычном бытовом смысле. Очередь – это такая структура, в которой для данных применяется правило «Первый вошел – первый вышел» или по-английски «First In – Fist Out», сокращенно FIFO. Элемент добавляется в хвост очереди, а извлекается из начала.

НЕ нашли? Не то? Что вы ищете?

Рассмотрим простой пример, иллюстрирующий применение стека для вычислений. Пусть нужно вычислить N! – факториал числа N. По определению . Для выполнения вычислений сначала поместим все значения N>0 в стек, а потом вычислим каждое промежуточное значение факториала, умножая предыдущее значение на извлекаемый из стека множитель.

Для работы с данными используем процедуры push – для проталкивания значения в стек и pop – для выталкивания из стека.

Программа

Комментарии

program stekfactorial;

type

stek=^element;

Описание типа указателя на элемент стека

element=record

Описание типа элемента стека

fn:real;

Информационное поле

down:stek

Указатель на предыдущий элемент

end;

Var

b, c:stek;

Описание статических указателей, b – вершина стека

n, i:integer;

nf, g:real;

procedure pop(var x:real);

Процедура выталкивания значения из стека в переменную x

Begin

c:=b;

Запомнили позицию верхнего элемента

x:=b^.fn;

Считали значение из стека

b:=b^.down;

Сместили указатель на следующий элемент в стеке

dispose(c);

Уничтожили извлеченный элемент

end;

procedure push(x:real);

Процедура помещения в стек значения x

Begin

new(c);

Создали новую переменную

c^.fn:=x;

Записали значение в новый элемент стека

c^.down:=b;

Установили указатель на предшествующий элемент

b:=c

Сдвинули указатель вершины стека

end;

Begin

readln(n);

Ввод значения переменной

i:=n;

b:=nil;

while i>=0 do

Цикл «пока» для помещения значений в стек.

Begin

if i=0 then push(1)

Поместить в стек 0!

else push(i);

Проталкивание значения множителя

i:=i-1;

Переход к следующему значению

end;

pop(nf);

Выталкивание значения 0! в переменную nf

while b<>nil do

Пока стек не пуст

Begin

pop(g);

Выталкиваем значение множителя в переменную g

nf:=nf*g

Находим следующее значение факториала

end;

writeln(nf)

Печатаем значение результата

end.

Двоичные деревья

Двоичные деревья – это структуры данных, которые также как и списки, стеки и очереди широко применяются в практике решения задач программирования. Строго говоря, двоичные деревья являются одним из типов ориентированных графов, не имеющих циклов, узлы которых связываются двумя ребрами с двумя другими узлами графа.

Типичным примером двоичного дерева является генеалогическое дерево, в котором узлом является человек, а ветви связывают его с его собственными родителями. Получается структура: человек, затем его отец и мать, родители отца и родители матери, родители родителей и так далее. Пример такого дерева приведен на рисунке.

Организационная диаграмма

Первый узел двоичного дерева называется корнем, а последние узлы, те из которых нет ребер к следующим, называются вершинами двоичного дерева.

Применение двоичных деревьев, не ограничивается генеалогией. К примеру, рассмотрим арифметическое выражение 2*2+11/2. Это выражение определяет, какие действия надо выполнить с операндами, а правила арифметики устанавливают порядок их выполнения. Каждой операции соответствует два операнда, а результат выполнения операции будет использован в качестве операнда в следующем вычислении или окажется окончательным – равным значению выражения. Для нашего выражения можно построить двоичное дерево аналогичное генеалогическому:

Организационная диаграмма

По мере вычислений происходит преобразование (сокращение) дерева.

Организационная диаграмма

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

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

Задача 3. Строкой задано арифметическое выражение, в записи которого используются только операции сложения и умножения. Написать программу вычисления значения этого выражения.

Решение. Задачу следует разбить на две части. Сначала построим двоичное дерево, соответствующее выражению, затем произведем вычисление значения.

Для решения первой части опишем процедуру с параметрами – указателем на узел и строкой, содержащей часть обрабатываемого выражения. В этой процедуре будем выяснять, есть ли в обрабатываемом выражении символы операций. Если операций нет, то значением узла станет строка, соответствующая числу-операнду и узел станет вершиной дерева. Если в строке присутствуют знаки операций, то один из них будет помещен в информационное поле узла. Затем будет создана пара новых узлов. Потом произойдет два рекурсивных вызова процедуры параметрами которых будут правая и левая часть строки от знака операции и соответствующие указатели на следующие левый и правый узел.

Для решения второй части задачи определим функцию, параметр которой указатель на узел двоичного дерева. Если узел является вершиной, то в его информационном поле хранится символьная запись числа, которое и станет значение функции. Если же узел является промежуточным, то в его информационном поле хранится символ операции. В этом случае значение функции будет вычисляться рекурсивно как сумма или разность функций, вызванных с параметрами-указателями на следующие правый и левый узлы.

Программа, реализующая этот алгоритм, приведена ниже.

Программа

Комментарии

program plusminus;

type

ukaz=^uzel;

Описание типа указателя на узел дерева

uzel=record

Описание типа узла дерева

inf:string[16];

Информационное поле

ukl, ukr:ukaz

Указатели на левый и правый следующие узлы

end;

var

a:ukaz;

Статическая переменная – указатель на корень

s:string;

Входная строка

i:integer;

y:real;

procedure stroim(st:string; var u:ukaz);

Процедура построения дерева

var

i:integer;

begin

if (pos('-',st)=0)and(pos('+',st)=0) then

Если в строке нет символов операций

begin

u^.inf:=st;

Информационное поле равно параметру st

u^.ukl:=nil;

Указатель на следующий nil – узел является

u^.ukr:=nil

вершиной дерева

end

else

begin

i:=length(st);

Начиная с последнего символа

while (st[i]<>'+')and(st[i]<>'-') do

ищем знак операции

i:=i-1;

u^.inf:=st[i];

Знак операции в информационное поле

new(u^.ukl);

Новый левый узел

new(u^.ukr);

Новый правый узел

stroim(copy(st,1,i-1),u^.ukl);

Строим левую ветвь

stroim(copy(st, i+1,length(st)-i),u^.ukr)

Строим правую ветвь

end

end;

function shet(u:ukaz):real;

Функция вычисления результата

begin

if u^.ukl=nil then

Если узел является вершиной

begin

val(u^.inf, y,i);

Преобразуем строку в число

shet:=y

Результат число

end

else

Иначе

case u^.inf[1] of

Если операция

'+': shet:=shet(u^.ukl)+shet(u^.ukr);

+, то результат сумма левого и правого

'-': shet:=shet(u^.ukl)-shet(u^.ukr)

-, то результат разность левого и правого

end

end;

begin

readln(s);

Вводим строку

new(a);

Создаем корень дерева

stroim(s, a);

Строим дерева

writeln(shet(a):15:5)

Печать значения функции

end.

Файлы

Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5