- •Указатели и динамическая память
- •Объявление указателей
- •Выделение и освобождение динамической память
- •Процедуры и функции для работы с динамической памятью
- •Динамические структуры данных Связные списки, стеки и очереди
- •Односвязные (однонаправленные)списки
- •Узлы связного списка
- •Создание односвязного списка
- •Вставка и удаление элементов в односвязном списке
- •Прохождение связного списка
- •Соображения по поводу эффективности
- •Двухсвязные списки
- •Соображения по поводу эффективности
- •Очередь
Соображения по поводу эффективности
Как и для односвязных списков, предварительно приведем некоторые соображения, касающиеся проблемы эффективности.
Использование начального и конечного узлов
Для односвязного списка было показано, что наличие начального узла существенно упрощало операции вставки и удаления. Соответствующий случай для двухсвязного списка - наличие двух фиктивных узлов: начального и конечного. Они позволяют очень легко выполнять прохождение списка от первого узла к последнему, равно как от последнего к первому. Специальные случаи при этом исключаются.
Стек
Стек— это структура данных, в которой добавление новых элементов и удаление существующих производится с одного конца, называемого вершиной стека или другими словами: реализована стратегия доступа " последний пришел – первый ушел" (LIFO – Last In First Out)
Простой пример: детская пирамидка. Процесс сборки и разборки пирамидки подобен процессу функционирования стека. В любой момент времени доступен лишь один элемент стека — верхний. Из определения следует, что извлекать элементы из стека можно только в порядке, обратном порядку их добавления в стек.
Основные операции со стеком:
запись элемента в стек,
извлечение элемента из стека,
проверка наличия элементов в стеке.
Cуществуют два варианта реализации стека: первый - на основе односвязного списка, второй - на основе массива.
Если использовать список для представления данных стека, то его можно определить как список, в котором добавление новых элементов и извлечение имеющихся происходит с начала (или конца) списка. Значением указателя, представляющего стек, является ссылка на вершину стека. Каждый элемент стека содержит поле ссылки на следующий элемент.
Таким образом, описать стек (элементом данных являются целые числа) можно следующим образом:
Type
DataType=integer;
nodePtr=^node;
node=Record
data: DataType;
next: nodePtr;
End;
Var
st: nodePtr;
Если стек пуст, то значение указателя st равно Nil.
Запись в стек.
Процедура записи элемента в стек должна содержать два параметра: первый определяет указатель на начало стека, второй — записываемое в стек значение.
Запись в стек производится аналогично вставке нового элемента в начало списка:
Procedure WriteStack(Var u:nodePtr; d:DataType);
Var
newNode:nodePtr;
Begin
New(newNode) ;
newNode^.data:=d;
newNode^.next:=u;
u:=newNode;
End;
Извлечение элемента из стека.
В результате выполнения этой операции некоторой переменной должно быть присвоено значение первого элемента стека и изменено значение указателя на начало списка.
Procedure ReadStack(Var u:nodePtr; Var d:DataType);
Var
tempNode:nodePtr;
Begin
d:=u^.Data;
tempNode:=u;
u:=u^.Next;
Dispose (tempNode) ;
End;
Недостатком описанной процедуры является предположение о том, что стек не пуст. Для его исправления следует разработать логическую функцию проверки пустоты обрабатываемого стека и перед использованием процедуры ReadStack проверять наличие элементов в стеке.
Function isFree (u:nodePtr):Boolean;
Begin
If u=Nil Then isFree:=True
Else isFree:= False;
End;
Пример
Написать программу, проверяющую соответствие открывающих и закрывающих скобок типа «(, ), {, }, [, ]» в строке символов.
Для решения задачи определим стек, элементами которого являются символы:
DataType=char;
В процессе решения анализируем символы строки a:string. Если встречена одна из открывающих скобок, то она записывается в стек. При обнаружении закрывающейся скобки, соответствующей скобке, находящейся в вершине стека, последняя удаляется. При несоответствии скобок выдается сообщение об ошибке, которое фиксируется в логической переменной.
Осталось выяснить, как определить, соответствует ли очередная закрывающая скобка скобке, находящейся в вершине стека. Оказывается, что коды соответствующих друг другу скобок отличаются не более чем на 2: { } имеют коды 123-125; [ ] — 91-93; () — 40-41, причем код открывающей скобки меньше. То есть выполнение условия If (Ord(a[i])-Ord(stack^ .data))<=2 Then... говорит о соответствии обрабатываемых скобок.
Program Parenth;
Type
DataType=char;
nodePtr=^node;
node=Record
data: DataType;
next: nodePtr;
End;
Var
s:String;
f :Boolean ;
Procedure WriteStack(Var u:nodePtr; d:DataType);
Var
newNode:nodePtr;
Begin
New(newNode) ;
newNode^.data:=d;
newNode^.next:=u;
u:=newNode;
End;
Procedure ReadStack(Var u:nodePtr; Var d:DataType);
Var
tempNode:nodePtr;
Begin
d:=u^.Data;
tempNode:=u;
u:=u^.Next;
Dispose (tempNode) ;
End;
Function isFree (u:nodePtr):Boolean;
Begin
If u=Nil Then
isFree:=True
Else
isFree:= False;
End;
Procedure Solve(a:String;Var pp:Boolean);
Var
head:nodePtr;
i:Integer;
ch:DataType;
Begin
head:=Nil;
pp:=True;
i:=1 ;
While (i<=Length (a)) And pp Do
Begin
If a[i] In ['(','[','{'] Then
WriteStack (head,a [i])
Else
Begin
If a[i] In [')',']','}'] Then
Begin
If not isFree(head) Then
Begin
ReadStack (head,ch);
If ABS (Ord(ch)-Ord(a[i])) >2 Then pp:=False;
End
Else pp:=False;
End;
End;
Inc(i);
End;
if not isFree(head) Then pp:=False
End;
Begin
WriteLn('Введите текст.');
ReadLn(s);
If s<>'' Then
Begin
Solve (s,f) ;
IffThenWriteLn('Строка записана правильно.')
ElseWriteLn('В строке содержится ошибка.');
End
Else
WriteLn('Строка пустая.');
ReadLn;
End.
