рефераты конспекты курсовые дипломные лекции шпоры

Реферат Курсовая Конспект

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

Стеки и очереди - раздел Транспорт, От автора Значение Стека Как Структуры Данных В Программировании Не Исчерпывается Лишь ...

Значение стека как структуры данных в программировании не исчерпывается лишь стеком отложенных заданий. В этом разделе мы решим с помощью стека задачу о вычислении значения арифметического выражения, заданного своей постфиксной (“польской”) записью. Пусть, например, требуется вычислить значение выражения ((6+7)*3)-(8*(9-5)), тогда его постфиксная запись будет иметь вид 67+3*895-*-. Алгоритм преобразования инфиксной (обычной) записи в постфиксную известен, он также использует стек, но здесь мы не будем его рассматривать. Поскольку числа в выражении могут состоять не только из одной цифры, мы примем постфиксную запись в виде #6#7+#3*#8#9#5-*- , где символ # означает начало очередного числа. Алгоритм решения этой задачи довольно прост и широко известен: будем брать из постфиксной записи по одному элементу (числу или знаку операции): если взято число, просто поместим его в стек, если взят знак операции, то возьмем из стека два числа, выполним над ними эту операцию и поместим результат в стек. Когда все элементы постфиксной записи обработаны, в стеке окажется значение выражения.

 

Type T_Num_Stack = Array[1..100] Of LongInt;

{В этой программе будем хранить стек в массиве}

Function Value_By_Postfix(Postfix:String):LongInt;

{Функция вычисляет значение выражения, заданного постфиксной записью.}

Function Get_From_Postfix

(Var Postfix:String; Var Op:Char; Var Val:LongInt):Boolean;

{Функция "забирает" из постфиксной записи очередной элемент (число или знак операции) и возвращает True, если это число, и False, если это знак операции. Отработанные символы удаляются из постфиксной записи, так что очередной символ всегда Postfix[1]}

Begin

If Postfix[1]='#' Then Begin {признак числа}

Get_From_Postfix:=True;

Delete(Postfix,1,1);

Val:=0;

While Postfix[1] In ['0'..'9'] Do Begin

{формируем число из цифр по схеме Горнера}

Val:=10*Val+Ord(Postfix[1])-Ord('0');

Delete(Postfix,1,1);

End;

End

Else Begin

Get_From_Postfix:=False;

Op:=Postfix[1];

Delete(Postfix,1,1);

End;

End;

Function Execute(op:Char;x1,x2:LongInt):LongInt;

{Функция выполняет арифметическую операцию, заданную знаком op}

Begin

Case op Of

'+': Execute:=x1+x2;

'-': Execute:=x1-x2;

'*': Execute:=x1*x2;

End;

End;

Var

Stack : T_Num_Stack; {стек для чисел}

Top : Byte; {номер первого элемента стека}

Op : Char;

x1,x2 : LongInt;

Number : Boolean;

Begin

Top:=0; {стек сделали пустым}

While True Do Begin

{условие окончания цикла будет проверено в теле цикла}

Number:=Get_From_Postfix(Postfix,Op,x1);

{взяли из постфиксной записи число или операцию}

If Number Then Begin {взяли число - помещаем его в стек}

Inc(Top);

Stack[Top]:=x1;

End

Else Begin {взяли операцию - извлекаем из стека два числа (обратите внимание, в каком порядке), выполняем над ними операцию и результат помещаем в стек}

x2:=Stack[Top];

Dec(Top);

x1:=Stack[Top];

Dec(Top);

Inc(Top);

Stack[Top]:=Execute(Op,x1,x2);

End;

If Postfix='' Then Begin {постфиксная запись пуста, теперь в стеке находится одно число, которое и есть значение выражения}

Value_By_Postfix:=Stack[Top];

Exit;

End;

End;

End;

Const Postfix : String='#6#7+#3*#8#9#5-*-';

Begin

WriteLn(Postfix,'=',Value_By_Postfix(PostFix));

End.

 

Еще раз внимательно посмотрим, как организовано хранение стека в массиве. Когда мы держали стек в списке, мы по-настоящему добавляли туда элементы и по настоящему удаляли элементы оттуда. Если стек размещен в массиве, то, конечно, этого делать не надо, достаточно лишь иметь одну дополнительную переменную, равную номеру “верхнего” элемента стека, в данной программе это переменная Top. Если стек пуст, то Top=0; чтобы добавить число в стек, достаточно увеличить Top на единицу и записать число в элемент с индексом Top. Чтобы удалить число из стека, достаточно просто уменьшить Top на единицу.

Еще одна структура данных, также уже известная нам, которая часто используется при решении различных задач, - это очередь, или FIFO-структура. Очередь отличается от стека тем, что элемент, попавший туда первым, и извлекается оттуда первым, а не последним, как в стеке. Очередь так же, как и стек, можно хранить и в списке, и в массиве. Реализация очереди в списке не представляет большой сложности, а вот хранение ее в массиве - не вполне тривиальная задача. Рассмотрим ее более подробно. Элементы очереди добавляются в “хвост” массива, а удаляются из “головы”, поэтому очередь по мере ее использования “ползет” по массиву слева направо и, если размер массива не очень велик, может достигнуть края массива, и тогда добавление нового элемента станет невозможным. Использование очень больших массивов, заведомо превышающих любые потребности очереди, неэкономно, а часто и невозможно. Гораздо лучше использовать “закольцованный” массив, в котором за последним элементом массива непосредственно следует первый его элемент. В этом случае очередь, достигнув конца массива, “переползет” в его начало, которое к этому моменту будет уже свободно. Пусть массив Q содержит N элементов, пронумерованных от 0 до N-1. В переменных Top и Len будем хранить номер “верхнего” элемента очереди и длину (количество элементов) очереди. В начальный момент очередь пуста иTop=Len=0. Чтобы добавить элемент в очередь, нужно записать добавляемый элемент в элемент массива Q[(Top+Len)Mod N],а затем увеличить Len на единицу, значение Top при этом не изменяется. Чтобы удалить элемент из очереди (всегда удаляется только первый элемент), нужно уменьшить Len на единицу и вычислить новое значение Top по формуле Top=(Top+1) Mod N. Решим, используя очереди, такую задачу: напечатать в порядке возрастания первые n натуральных чисел, в разложение которых на простые множители входят только числа 2, 3 и 5. Будем хранить очереди в массивах. Один из алгоритмов решения этой задачи таков: организуем три очереди Q2,Q3 и Q5. Выведем число 1 и добавим в очередь Q2 число 2, в Q3 число 3 и в Q5 число 5. Затем в цикле от 2 до n:

- найдем элемент m, наименьший из первых элементов очередей;

- удалим этот элемент из всех очередей, где он является первым;

- выведем этот элемент и добавим в Q2 число 2m, в Q3 число 3m и в Q5 число 5m.

 

Const n=240;

Type Queue = Object {объект - очередь}

Body : Array[0..n-1] Of LongInt;

Top : 0..n-1;

Len : 0..n;

Procedure Clear;

Procedure Add(x:LongInt);

Procedure Get(Var x : LongInt);

Function Upper : LongInt;

End;

Procedure Queue.Clear; {процедура делает очередь пустой}

Begin

Len:=0;

Top:=0;

End;

Procedure Queue.Add(x:LongInt); {процедура добавляет элемент в очередь}

Begin

Body[(Top+Len)Mod n]:=x;

Inc(Len);

End;

Procedure Queue.Get(Var x : LongInt);

{процедура забирает элемент из очереди}

Begin

x:=Body[Top];

Top:=(Top+1) Mod n;

Dec(Len);

End;

Function Queue.Upper:LongInt;

{функция возвращает первый элемент очереди, но не удаляет его}

Begin

Upper:=Body[Top];

End;

Procedure Add_And_Print(t:LongInt; Var Q2,Q3,Q5:Queue);

Begin

Write(t:8);

Q2.Add(2*t);

Q3.Add(3*t);

Q5.Add(5*t);

End;

Var

Q2,Q3,Q5 : Queue;

m,x : LongInt;

k : Word;

Begin

Q2.Clear; {делаем все очереди пустыми}

Q3.Clear;

Q5.Clear;

Add_And_Print(1,Q2,Q3,Q5);

{выводим 1 и добавляем в очереди 2,3,5}

k:=1;

While k<n Do Begin

m:=Q2.Upper; {находим наименьший из первых элементов}

If m>Q3.Upper Then m:=Q3.Upper;

If m>Q5.Upper Then m:=Q5.Upper;

Add_And_Print(m,Q2,Q3,Q5);

{выводим его и добавляем новые элементы в очереди}

If m=Q2.Upper Then Q2.Get(x);

{удаляем первый элемент, если он равен m}

If m=Q3.Upper Then Q3.Get(x);

If m=Q5.Upper Then Q5.Get(x);

Inc(k);

End;

WriteLn;

End.

– Конец работы –

Эта тема принадлежит разделу:

От автора

B r... Теперь мы можем присвоить переменным их значения...

Если Вам нужно дополнительный материал на эту тему, или Вы не нашли то, что искали, рекомендуем воспользоваться поиском по нашей базе работ: Стеки и очереди

Что будем делать с полученным материалом:

Если этот материал оказался полезным ля Вас, Вы можете сохранить его на свою страничку в социальных сетях:

Все темы данного раздела:

От автора
Первое издание этой книги вышло в свет в 1997 году и довольно быстро стало библиографической редкостью. Автор несколько неожиданно для себя обнаружил, что книга пользуется черезвычайно высоким спро

Round(x) - округленное до целого вещественное число, преобразованное к типуLongInt
6. Sqr(x) - квадрат числа 7. Sqrt(x) - квадратный корень 8. Exp(x) - экспонента 9. Ln

Символьный тип данных
Для хранения символьной информации в Паскале предусмотрен специальный тип данных Char. Допустимы переменные, нетипизированные и типизированные константы такого типа. Данные типа

Caseвыражение Of
список значений : оператор/блок .................................. список значений: оператор/блок

Процедуры и функции. Сфера действия описаний
В языке Паскаль (как вы уже поняли из предыдущего материала) существуют понятия процедуры и функции. Процедуры и функции можно определить как замкнут

Открытые массивы и нетипизированные параметры
Из предыдущего раздела мы узнали, что параметры подпрограмм описываются как [Var] имя : имя типа , это правда, но не вся правда - существует еще два

Множества
Понятие множества в Паскале очень близко к математическому определению: множество - это совокупность однотипных неиндексированных объектов. Множества

Графические средства языка Паскаль
Монитор персонального компьютера может работать в двух режимах - текстовом и графическом. Все, что мы делали до сих пор, мы делали в текстовом режиме. Текстовый экран содержит 2000 знако

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

Case тип Of
константа 1 : (описание поля); константа 2 : (описание поля); .....................

Модуль Crt
Crt - еще один стандартный модуль Паскаля, в котором содержатся разнообразные средства консольного ввода-вывода (то есть ввода с клавиатуры и вывода на текстовый экран). Процедуры

Var TextAttr : Byte
В ней содержится текущий цвет фона и цвет символов, используемые при выводе на экран процедурами Write иWriteLn. Изменив эту переменную, вы задаете новый

Другие средства обработки файлов и модуль DOS
Для того чтобы определить, есть ли на диске файл с заданным именем, удобно использовать уже известную нам стандартную функцию IOResult , которая возвращает ноль при успешном завершении последней оп

Type SearchRec=Record
Fill : Array[1..21] of Byte; Attr : Byte; Time : LongInt; Size : LongInt; Name : Stri

Процедурные типы
Язык Паскаль позволяет использовать в программе данные типа “процедура” или типа “функция”. Такие данные можно передавать как аргументы подпрограмм, можно описывать и использовать массивы процедур

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

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

Открытые строки
  Открытыми строками, или длинными строками, или C-строками, называются символьные последовательности длиной до 65535 символов, ограниченные справа нуль-символ

Использование командной строки и вызов внешних программ
Паскаль позволяет передавать информацию в программу при ее запуске через командную строку. Для этого служат две стандартные функции -ParamCount и ParamStr.

Обработка программных прерываний
Программное прерывание - это ситуация, возникающая, когда дальнейшее выполнение программы невозможно. Например, деление на ноль, переполнение, ошибка Range check error, обращение по неверному адрес

Объекты
Объектом в языке Паскаль называется совокупность данных и подпрограмм, обрабатывающих эти данные. Программирование с использованием объектов называется объектно-о

Type имя типа=Object
описание полей описание методов End; Поля объектов описываются так же, как поля записей, а описание метода - это заголовок процедуры или функции. Сами методы распол

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

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

Комбинаторные алгоритмы
В этом разделе мы рассмотрим три наиболее важные задачи комбинаторики: нахождение всех подмножеств множества из n элементов; нахождение всех выборок по m элементов из n элементов и нахождение всех

Бинарные деревья
В этом разделе мы рассмотрим различные алгоритмы обхода бинарного дерева. К алгоритмам создания бинарного дерева мы обратимся несколько позже, а пока будем считать, что дере

Упорядоченные бинарные деревья и приоритетные очереди
Упорядоченным бинарным деревом, или бинарным деревом поиска, называют дерево, в любой части которого элементы левого поддерева меньше корневого элеме

Алгоритмы сортировки
В этом разделе мы рассмотрим различные алгоритмы решения задачи сортировки. Задача сортировки ставится следующим образом: дана последовательность записей R1,R

Хотите получать на электронную почту самые свежие новости?
Education Insider Sample
Подпишитесь на Нашу рассылку
Наша политика приватности обеспечивает 100% безопасность и анонимность Ваших E-Mail
Реклама
Соответствующий теме материал
  • Похожее
  • Популярное
  • Облако тегов
  • Здесь
  • Временно
  • Пусто
Теги