Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
AlgStr / Практические занятия / Линейные структуры / Практическая работа №4.doc
Скачиваний:
35
Добавлен:
23.03.2015
Размер:
237.06 Кб
Скачать

4) Стек на базі масиву

type

T = <опис типа Т>

stack_T = record

size: word

TopInd: word

Pbody: ^body;

end;

Body=array[1..65536 div SizeOf(T)] of T;

{stack_T=data type is Create,Push,Pop,IsEmpty,Done}

Опис: Stack_T - це змінні стеки елементів типу Т. Операції Push і Pop змінюють стан стека.

Procedure Create(Var S:Stack_T; size_stask:word);

Requires 0sizeStask65535 div sizeof(T)

Effects створюють порожній стек елементів типу Т з розміром в sizestask елементів типу Т

Procedure Push(Var S:Stask_T;X:T);

Requires S - містить менше елементів, чим S.size

Modifies S

Effects заштовхує елемент X в стек S

Procedure Pop (Var S:Stask_T);

Requires S – непорожній

Modifies S

Effectsвиштовхує елемент з вершини стека

Function Top (S:Stask_T):T;

RequiresS- непорожній

Effects повертає елемент, що знаходиться у вершині стеку.

Function IsEmpty(S:Stask_T):boolean;

Effects IsEmpty=S=порожній стек

Procedure Done (Var S:Stask_T);

Effects звільняє пам'ять, займану тілом стека, і приводить дескриптор у неробочий стан.

Implementation

{ Функція абстракції:

Типовий стек є послідовність елементів e1,e2,…,en, де n - вершина стека (тобто стек росте у напрямку старших індексів масиву PBody). }

{ Функція інваріант подання:

1  size  65535 div sizeof(T) & 0  TopInd  size & PBody^[TopInd] - елемент у вершині стека. Pbody вказує на вектор пам'яті розміром size*sizeof(T) }

Procedure Create;

BEGIN

if sizeStaskSizeOf (T) > 65536 then Halt(1);

GetMem (S.Pbody^sizeStask SizeOf (T));

S.TopInd :=0;

S.Size := sizeStask;

END;

Procedure Push;

BEGIN

inc(S.TopInd);

S.Pbody^[S.TopInd] :=X;

END

Класичний приклад на використання стека:

Хай маємо ( (х+2)+3-3*(х+3) )*х

0 1 1 2 1 0

// Перевірити правильність розстановок дужок

Якщо дужки різного вигляду:

([х+2]+3-3*[х+3])*х

Використовуємо стек для зберігання дужок, що відкрилися. Якщо закриваємо дужки, то перевіряємо є на верх стека що така ж відкривається.

Черга елементів типу ℓ .

Додавання в Tail, вибірка з Head.

Необхідно реалізувати об'єкт типу черга.

type

TQueue=object

procedure create; методи (поведінка)

function Empty:boobcan;

procedure EnQ(U: E); // додати в хвіст

procedure DeQ(var U: E); // видалення з голови

function Head E;

function Tail E; // заглянути в чергу

.

.

.

procedure Down // зруйнувати чергу

end;

Існує два способи реалізації:

1.Обмежена черга на базі масиву;

2.Необмежена черга на базі списку.

Обмежена черга на базі масиву:

Head = <указує індекс елементу, звідки необхідно читати >

Tail = <указує на останній записаний елемент >

Ці покажчики будуть повзти по массиву, однак у процесі роботи виникає питання, що робити, коли хвістдоповзе до кінця масиву ?

Існує два способи:

  1. Перемістити всю чергу на початок – ПОГАНО.

  2. Наступний елемент помістити у початок – КРАЩЕ. Однак в цьому випадку стають не помітні два випадки:

  • Коли черга порожня: покажчик голови буде на 1 більше покажчика хвоста

  • Переповнення черги.

Необхідно продумати як виглядатиме порожня черга:

Приймемо, що порожня черга виглядає: Head=0

Tail=size -1

Розглянемо проміжний випадок:

Нехай:

Нехай я 1) ПИШУ, тоді Head залишиться незмінним, а

Tail необхідно просунути на 1.

2) ЧИТАЮ: Head зрушую на наступний, а Tail не

зміниться.

Уявимо, що я тільки ПИШУ, то Tail доповзе до кінця, тоді необхідно писати з початку і у нас змійка постійно бігатиме

Нехай:

Head=Tail+1 (ознака переповнювання)

Або випадок:

читаємо, читаємо, виходить

получаем

ознака порожнечі

Що робити, якщо Tail знаходиться в кінці. Для цього пропонують загнути чергу в бублик за допомогою операції:

Next(i)= i+1, якщо i<size-1

0 , якщо i>=size-1

Виникають проблеми з неоднозначністю. Подивимося на операції ПИСАТИ і ЧИТАТИ.

Коли я ПИШУ, тоді умову Next, проверяю перед операцією, а коли ЧИТАЮ - тоді після.

Для цього ми на підставі черги додаємо до опису булеве поле Empty.

Empty:

Запишемо алгоритм читання і запису на псевдокоді.

Пишу:

ЯКЩО Head=Next(Tail)

ТОДІ

ЯКЩО Empty тоді

Tail=Next(Tail) та

Пишу на місце Tail і скидаю прапор Empty // в false

ІНАКШЕ помилка переповненої черги

ВСЕ ЯКЩО

Читаю:

ЯКЩО Empty ТОДІ

Помилка - пустота черги

ІНАКШЕ

Читаю з місця Head

і просуваю Head = Next(Head)

ЯКЩО head=Next(Tail) ТОДІ

Empty = True

ВСЕ ЯКЩО

При роботі з чергою необхідно перевіряти чергу на виявлення наступних ситуацій:

  1. Не допускати заповнення масиву до кінця.

Head<>Next(Tail)

  1. Завести Спеціальний признак порожнечі черги. Перевіряти його перед вибіркою та встановлювати (якщо потрібно)після вибірки.

  2. Замість того, щоб зберігати покажчик на хвіст і голову, то ми можемо зберігати покажчик на голову і кількість елементів - [size].

Недолік цього – немає явного покажчика на хвіст.

Перевага – просто розпізнаються операції переповнення та порожнечі черги.

Реалізація черги на базі списку

Виникає питання: Де зберігати Head і Tail ?

Ідея 1: Необхідно зберігати покажчик на голову і хвіст, тобто

Наприклад: необхідно читати

- запом’ятовуємо Head в P;

- виправляємо Head Next(Head);

- видати Dispose для цього вузла.

Якщо необхідно писати:

-видаляємо вузол і запам'ятовую в Р;

В цьому випадку виникають проблеми, наприклад: якщо черга порожня.

Для вирішення необхідно ввести фіктивний вузол, для того, щоб не допускати до порожнечі.

Ідея 2: Зберігати покажчик на хвіст

Tail указує на хвіст

Таким чином, в цьому випадку кільцевий список. Але тут теж виникають проблеми: переповнювання і спустошення.

Послідовність.

Послідовність - послідовний файл в оперативній пам'яті. Елементи послідовності в кожний момент часу розділені на дві частини – прочитану та не прочитану.

Після створення послідовності прочитана і непрочитана частина є порожніми. При додаванні елементу в послідовності він додається в кінець. При цьому непрочитана частина збільшується, а прочитана не змінюється. Запис в послідовність йде тільки в кінець. По операції “встати в початок послідовності” (Reset) прочитана частина стає порожньою, а непрочитана частина співпадає зі всією послідовністю. Непрочитана частина поводиться як черга.

Цю структуру можно реализовать на базі 2-х стеків:

Реализация последовательности на базе 2-х стеков:

Початкова ситуація:

0 0 0 0 0 0

Ситуація читання:

0 0

0 0 0 0 0 0

Читаю:

0 0 0

0 0 0 0 0 0

Реалізація об'єкту типу послідовність.

Type

SEQ =object

LeftQ, RightQ : QueneE;

procedure Create;

procedure ReWrite;

procedure Reset;

procedure Write(El:E);

procedure Read(var El:E);

procedure Skip;

function Empty:boolean;

function EQSeg: boolean;

function CurEl;

procedure Done;

end;

procedure SEQ.Create;

begin

LeftQ.Create;

Right.Create;

end;

procedure ReWrite;

var El: E;

begin

while not LeftQ.Empty do

LeftQ.DeQ(El);

while not RightQ.Empty do

RightQ.DeQ(El);

end;

procedure Reset;

begin

while not RightQ.Empty do

begin

RightQ.DeQ(El);

LeftQ.EnQ(El);

end;

while not LeftQ.Empty do

begin

LeftQ.DeQ(El);

RightQ.EnQ(El);

end;

end;

procedure Write(El:E);

begin

RightQ.EnQ(El);

end;

procedure Read(var El:E);

begin

RightQ.DeQ(El);

LeftQ.EnQ(El);

end;

procedure Skip;

var El: E;

begin

RightQ.DeQ(El);

LeftQ.EnQ(El);

end;

function Empty:boolean;

begin

Empty:=LeftQ.Empty and RightQ.Empty

end;

function EQSeg: boolean;

begin

EQSeg:= RightQ.Empty;

end;

function CurEl:E;

begin

CurEl:= RightQ.Head;

end;

procedure Done;

begin

LeftQ. Done;

RightQ.Done;

end;

Еластична стрічка.

Еластична стрічка - Структура з однією головкою читання-запису, яка може пересуватися за стрічкою з можливістю вставки/видалення елементу у(з) будь-якого місця стрічки, на яке вказує голівка. Стрічка може необмежено розтягуватися та стискуватися у місці де розташована голівка.

При читанні елементу він завжди видаляється зі стрічки.

Реализация об'єкта типу еластична стрічка.

Elastic=object

CurList:NotePtr;

EoList: NotePtr;

procedure Create;

function Empty:boolean;

procedure Write(El:E);

procedure Read(var El:E);

procedure SkipLeft;

procedure SkipRight;

function EOLeft: boolean;

function EORight: boolean;

function CurEl;

procedure Done;

end;

Для реалізації cтрічки зручно використовувати двухнаправлений лінійний список:

Порожня, якщо Current=EOList

та Current.^Prev=nil

ліворуч порожня, якщо Current.^Prev=nil

праворуч порожня, якщо

Current=EOList

MakePtr = ^Node

Node = record

Prev:NodePtr;

Elem:E;

Next:NodePtr;

End;

Дек (DEQ) – двовхідна черга (Double-Ended-Quene).

Різновиди деку:

дек з обмеженим входом - архів;

дек з обмеженим виходом - перелік або реєстр.

Реализация об'єкта типу дек:

DEQuene=object

procedure Init;

function Empty:boolean;

procedure EnQTail(El:E);

procedure DeQTail( var El:E);

procedure EnQHead(El:E);

procedure DeQHead( var El:E);

function Head:E;

function Tail:E;

procedure Done;

end;

Фізичне подання:

  • обмежений дек на базі масиву;

  • необмежений дек на базі лінійного двухнаправленого списку.

Для реалізації cтрічки зручно використовувати двухнаправлений лінійний список:

Порожня, якщо Current=EOList

та Current.^Prev=nil

ліворуч порожня, якщо Current.^Prev=nil

праворуч порожня, якщо

Current=EOList

MakePtr = ^Node

Node = record

Prev:NodePtr;

Elem:E;

Next:NodePtr;

End;

Соседние файлы в папке Линейные структуры