Чтение онлайн

на главную - закладки

Жанры

Программирование на языке Ruby
Шрифт:

Но можно без труда определить класс

Stack
так, что к элементам можно будет обращаться только законно. И мы покажем, как это сделать.

Стоит отметить, что во многих алгоритмах стек применяется как основа элегантного рекурсивного решения. Причина станет ясна, если чуточку подумать. При вызове функции или метода параметры заталкиваются в системный стек и выталкиваются из него при возврате. Таким образом, рекурсивный алгоритм просто подменяет явно определенный пользователем стек системным. Что лучше? Зависит от того, какое значение вы придаете понятности программы, ее эффективности и другим аспектам.

Очередь организована по принципу «первым пришел, первым обслужен» (FIFO — first-in first-out). Аналогом может служить очередь за билетами в театр: вновь подходящие становятся в конец очереди, а те, кто пришел раньше, обслуживаются первыми. В программировании очереди используются реже, чем стеки.

Очереди полезны в системах реального времени, когда события нужно обрабатывать в порядке возникновения. Находят они применение и в ситуации «производитель-потребитель» (особенно в многопоточных программах и многозадачных средах). Неплохой пример — очередь к принтеру: задания на печать помещаются в один конец и ожидают, пока не будут извлечены с другого конца.

Две основные операции над очередью называются «поместить» (enqueue) и «извлечь» (dequeue). Им соответствуют методы

unpush
и
shift
в классе
Array
.

Отметим, что метод

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

На этом мы закончим введение в стеки и очереди. Самое время рассмотреть некоторые примеры.

9.2.1. Более строгая реализация стека

Мы обещали показать, как можно сделать стек защищенным от некорректного доступа. Выполняем обещание! Вот пример простого класса, который хранит внутри себя массив и управляет доступом к этому массиву. (Есть и другие способы, например делегирование, но описанная реализация проста и прекрасно работает.)

class Stack

 def initialize

@store = []

 end

 def push(x)

@store.push x

 end

 def pop

@store.pop

 end

 def peek

@store.last

 end

 def empty?

@store.empty?

 end

end

Мы добавили одну операцию, которая для массивов не определена; метод

peek
возвращает элемент, находящийся на вершине стека, не выталкивая его.

Нижеследующие примеры подтверждают адекватность такого определения класса.

9.2.2. Обнаружение несбалансированных скобок

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

def paren_match(str)

 stack = Stack.new

 lsym = "{I(<"

 rsym = "}])>"

 str.each_byte do |byte|

sym = byte.chr

if lsym.include? sym

stack.push(sym)

elsif rsym.include? sym

top = stack.peek

if lsym.index(top) != rsym.index(sym)

return false

else

stack.pop

end

# Игнорируем символы, отличные от скобок...

end

 end

 # Убедимся, что стек пуст...

 return stack.empty?

end

str1 = "(((a+b))*((c-d)-(e*f))"

str2 = "[[(a-(b-c))], [[x,y]]]"

paren_match str1 # false

paren_match str2 # true

Наличие вложенности естественным образом наводит на мысль о применении стека. Чуть сложнее распознать несбалансированные теги в HTML- или XML-документе. Лексемы состоят из нескольких символов, но логическая структура задачи остается той же самой. Вот еще типичные примеры задач, требующих стека: преобразование выражений из инфиксной формы в постфиксную (и наоборот), вычисление постфиксного выражения (как делается в виртуальной машине Java и многих других интерпретаторах) и вообще любая задача, имеющая рекурсивное решение. В следующем разделе мы немного поговорим о связи между стеком и рекурсией.

9.2.3. Стек и рекурсия

В качестве примера изоморфизма, существующего между стеком и рекурсией, рассмотрим классическую задачу о Ханойской башне.

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

Попутно разоблачим миф. Похоже, что на самом деле эту задачу впервые сформулировал французский математик Эдуард Люка в 1883 году, и никаких истоков в восточной культуре она не имеет. Сам Люка называл ее «Ханойской башней».

Поделиться:
Популярные книги

Искусство войны

Иванов Владимир
Фантастика:
космическая фантастика
5.00
рейтинг книги
Искусство войны

Афоризмы

Ермишин Олег
Справочная литература:
энциклопедии
6.57
рейтинг книги
Афоризмы

Избранное

де Кеведо-и-Вильегас Франсиско
Старинная литература:
европейская старинная литература
6.25
рейтинг книги
Избранное

Восьмое Небо

Соловьев Константин Сергеевич
Фантастика:
фэнтези
юмористическая фантастика
5.25
рейтинг книги
Восьмое Небо

Афганский полигон

Кулаков Сергей Федорович
Спецназ. Группа Антитеррор
Детективы:
боевики
6.17
рейтинг книги
Афганский полигон

Дракон на границе

Диксон Гордон Руперт
3. Дракон и Джордж
Фантастика:
фэнтези
6.25
рейтинг книги
Дракон на границе

Открытие мира (Весь роман в одной книге)

Смирнов Василий Александрович
Проза:
классическая проза
русская классическая проза
советская классическая проза
5.00
рейтинг книги
Открытие мира (Весь роман в одной книге)

Изгой. Трилогия

Михайлов Дем Алексеевич
Изгой
Фантастика:
фэнтези
8.45
рейтинг книги
Изгой. Трилогия

Последний реанорец. Том VIII

Павлов Вел
7. Высшая Речь
Фантастика:
фэнтези
попаданцы
аниме
5.75
рейтинг книги
Последний реанорец. Том VIII

Дважды одаренный. Том VI

Тарс Элиан
6. Дважды одаренный
Фантастика:
аниме
альтернативная история
фэнтези
фантастика: прочее
5.25
рейтинг книги
Дважды одаренный. Том VI

Бояръ-Аниме. Газлайтер. Том 35

Володин Григорий Григорьевич
35. История Телепата
Фантастика:
аниме
боевая фантастика
фэнтези
6.25
рейтинг книги
Бояръ-Аниме. Газлайтер. Том 35

Лейб-хирург

Дроздов Анатолий Федорович
2. Зауряд-врач
Фантастика:
альтернативная история
7.34
рейтинг книги
Лейб-хирург

Я до сих пор не царь. Книга XXVII

Дрейк Сириус
27. Дорогой барон!
Фантастика:
юмористическое фэнтези
аниме
попаданцы
5.00
рейтинг книги
Я до сих пор не царь. Книга XXVII

Ты - наша

Зайцева Мария
1. Наша
Любовные романы:
современные любовные романы
эро литература
5.00
рейтинг книги
Ты - наша