Я столкнулся с этим вопросом в книге алгоритмов ( Алгоритмы, 4-е издание Роберта Седжвика и Кевина Уэйна).
Очередь с тремя стеками. Реализуйте очередь с тремя стеками, чтобы каждая операция очереди занимала постоянное (в худшем случае) количество операций стека. Предупреждение: высокая степень сложности.
Я знаю, как сделать очередь с 2 стеками, но не могу найти решение с 3 стеками. Любая идея ?
(о, и это не домашняя работа :))
algorithm
data-structures
DuoSRX
источник
источник
Ответы:
РЕЗЮМЕ
ПОДРОБНОСТИ
За этой ссылкой есть две реализации: http://www.eecs.usma.edu/webs/people/okasaki/jfp95/index.html.
Одним из них является O (1) с тремя стеками, НО он использует отложенное выполнение, что на практике создает дополнительные промежуточные структуры данных (замыкания).
Еще один из них - O (1), но использует стеки SIX. Тем не менее, это работает без ленивого исполнения.
ОБНОВЛЕНИЕ: статья Окасаки находится здесь: http://www.eecs.usma.edu/webs/people/okasaki/jfp95.ps и кажется, что он фактически использует только 2 стека для версии O (1), которая имеет ленивую оценку. Проблема в том, что он действительно основан на ленивой оценке. Вопрос в том, можно ли его преобразовать в алгоритм 3 стека без ленивых вычислений.
ОБНОВЛЕНИЕ: Еще один связанный алгоритм описан в статье Хольгера Петерсена «Стеки против Deques», опубликованной в 7-й ежегодной конференции по вычислительной технике и комбинаторике. Вы можете найти статью из Google Книг. Проверьте страницы 225-226. Но алгоритм на самом деле не симуляция в реальном времени, это симуляция двухсторонней очереди из трех стеков в линейном времени.
gusbro: "Как сказал @Leonel несколько дней назад, я подумал, что было бы справедливо проверить у профессора Седжвика, знает ли он решение или была ли какая-то ошибка. Поэтому я написал ему. Я только что получил ответ (хотя и не от сам, но от коллеги из Принстона), поэтому я хотел бы поделиться со всеми вами. Он в основном сказал, что он не знал ни одного алгоритма, использующего три стека И другие наложенные ограничения (например, не используя ленивую оценку). Он знал об алгоритме, использующем 6 стеков, как мы уже знаем, глядя на ответы здесь. Поэтому я думаю, что вопрос все еще открыт, чтобы найти алгоритм (или доказать, что он не может быть найден). "
источник
rotate
это выглядитfront
список получает назначение в обоихoldfront
иf
, и которые затем изменены отдельно.Хорошо, это действительно сложно, и единственное решение, которое я мог придумать, помнит меня о решении Киркса для теста Кобаяси Мару (каким-то образом обманутым): Идея в том, что мы используем стек стеков (и используем его для моделирования списка ). Я называю операции en / dequeue и push и pop, тогда мы получаем:
(StackX = StackY - это не копирование содержимого, это просто копия ссылки. Это просто для того, чтобы описать это легко. Вы также можете использовать массив из 3 стеков и обращаться к ним через индекс, там вы просто измените значение индексной переменной ). Все в O (1) в терминах стековых операций.
И да, я знаю его argueable, потому что мы имеем неявную более 3-х стеков, но, возможно, дать другим из вас хороших идей.
РЕДАКТИРОВАТЬ: Пример объяснения:
Я попробовал здесь с небольшим ASCII-искусством показать Stack1.
Каждый элемент упакован в один стек элементов (поэтому у нас есть только стеки безопасных стеков).
Вы видите, чтобы удалить, мы сначала выталкиваем первый элемент (стек, содержащий здесь элементы 1 и 2). Затем вставьте следующий элемент и разверните там 1. Впоследствии мы говорим, что первый всплывающий стек - теперь наш новый Stack1. Говоря немного более функционально - это списки, реализованные стеками из 2 элементов, где верхний элемент ist cdr, а первый / нижний верхний элемент - car . Другие 2 помогают стекам.
Esp tricky - это вставка, так как вам нужно как-то погрузиться глубоко во вложенные стеки, чтобы добавить еще один элемент. Вот почему Stack2 там. Stack2 всегда самый внутренний стек. Добавление - это просто вставить элемент внутрь, а затем вставить новый Stack2 (и поэтому нам не разрешается касаться Stack2 в нашей операции удаления очереди).
источник
Я попытаюсь доказать, что это невозможно.
Предположим, что есть очередь Q, которая моделируется 3 стеками, A, B и C.
Утверждения
ASRT0: = Кроме того, предположим, что Q может моделировать операции {очередь, очередь} в O (1). Это означает, что существует определенная последовательность нажатий / выталкиваний стека для каждой моделируемой операции очереди / очереди.
Без ограничения общности предположим, что операции с очередями являются детерминированными.
Пусть элементы, поставленные в очередь в Q, будут пронумерованы 1, 2, ..., в зависимости от их порядка очереди, причем первый элемент, помещенный в очередь в Q, определен как 1, второй - как 2, и так далее.
определять
Q(0) :=
Состояние Q, когда в Q есть 0 элементов (и, следовательно, 0 элементов в A, B и C)Q(1) :=
Состояние Q (и A, B и C) после 1 очереди работы наQ(0)
Q(n) :=
Состояние Q (и A, B и C) после n операций очереди наQ(0)
определять
|Q(n)| :=
количество элементов вQ(n)
(следовательно|Q(n)| = n
)A(n) :=
состояние стека A, когда состояние QQ(n)
|A(n)| :=
количество элементов вA(n)
И аналогичные определения для стеков B и C.
Тривиально,
|Q(n)|
явно неограничен по п.Поэтому, по крайней мере , один из
|A(n)|
,|B(n)|
или|C(n)|
не ограничена на п.WLOG1
предположим, что стек A неограничен, а стеки B и C ограничены.Определить *
B_u :=
верхнюю границу B *C_u :=
верхнюю границу C *K := B_u + C_u + 1
WLOG2
, для n такого, что|A(n)| > K
выберите K элементов изQ(n)
. Предположим, что 1 из этих элементов находится воA(n + x)
всехx >= 0
, т. Е. Элемент всегда находится в стеке A независимо от того, сколько операций очереди выполнено.X :=
этот элементТогда мы можем определить
Abv(n) :=
количество предметов в стекеA(n)
выше XBlo(n) :=
количество элементов в стекеA(n)
ниже X| А (п) | = Abv (n) + Blo (n)
ASRT1 :=
Количество всплывающих окон, требуемых для удаления X изQ(n)
, по крайней мереAbv(n)
From (
ASRT0
) и (ASRT1
)ASRT2 := Abv(n)
должны быть ограничены.Если он
Abv(n)
не ограничен, то, если для удаления X требуется 20 декеевQ(n)
, потребуется как минимумAbv(n)/20
всплывающие окна. Который неограничен. 20 может быть любой константой.Следовательно,
должен быть неограниченным.
WLOG3
мы можем выбрать K элементов снизуA(n)
, и один из них находится вA(n + x)
для всехx >= 0
X(n) :=
этот элемент, для любого данного пВсякий раз, когда элемент находится в очереди в
Q(n)
...WLOG4
предположим, что B и C уже заполнены до их верхних границ. Предположим, что верхняя граница для элементов вышеX(n)
достигнута. Затем новый элемент входит в А.WLOG5
, предположим, что в результате новый элемент должен войти нижеX(n)
.ASRT5 :=
Количество всплывающих окон, необходимых для размещения элемента нижеX(n) >= Abv(X(n))
От
(ASRT4)
,Abv(n)
неограничен по п.Поэтому количество всплывающих окон, необходимых для размещения элемента ниже,
X(n)
не ограничено.Это противоречит
ASRT1
, следовательно, невозможно моделироватьO(1)
очередь с 3 стеками.Т.е.
По крайней мере 1 стек должен быть неограниченным.
Для элемента, который остается в этом стеке, число элементов над ним должно быть ограничено, иначе операция удаления из очереди для удаления этого элемента будет неограниченной.
Однако, если количество элементов над ним ограничено, то оно достигнет предела. В какой-то момент новый элемент должен войти под ним.
Поскольку мы всегда можем выбрать старый элемент из числа одного из самых низких элементов этого стека, над ним может быть неограниченное количество элементов (в зависимости от неограниченного размера неограниченного стека).
Чтобы ввести новый элемент под ним, поскольку над ним находится неограниченное количество элементов, требуется неограниченное количество всплывающих окон, чтобы поместить новый элемент под ним.
И поэтому противоречие.
Есть 5 WLOG (без потери общности) заявлений. В некотором смысле, они могут быть интуитивно поняты, чтобы быть правдой (но, учитывая, что они 5, это может занять некоторое время). Формальное доказательство того, что общность не потеряна, может быть получено, но оно чрезвычайно длинное. Они опущены.
Я признаю, что такое упущение может оставить под сомнением заявления WLOG. С паранойей программиста за ошибки, пожалуйста, проверьте операторы WLOG, если хотите.
Третий стек также не имеет значения. Важно то, что есть набор ограниченных стеков и набор неограниченных стеков. Минимум, необходимый для примера, составляет 2 стека. Количество стеков должно быть, конечно, конечным.
Наконец, если я прав, что нет доказательств, тогда должно быть доступное более простое доказательство. Вероятно, основано на том, что происходит после каждой очереди (следите за тем, как это влияет на наихудший случай удаления очереди, учитывая набор всех элементов в очереди).
источник
Примечание. Это комментарий к функциональной реализации очередей реального времени (наихудшего случая с постоянным временем) с односвязными списками. Я не могу добавлять комментарии из-за своей репутации, но было бы хорошо, если бы кто-то мог изменить это на комментарий, добавленный к ответу antti.huima. Опять же, это несколько долго для комментария.
@ antti.huima: связанные списки - это не то же самое, что стек.
s1 = (1 2 3 4) --- связанный список с 4 узлами, каждый из которых указывает на один справа, и содержит значения 1, 2, 3 и 4
s2 = выскочил (s1) --- s2 сейчас (2 3 4)
В этот момент s2 эквивалентен popped (s1), который ведет себя как стек. Тем не менее, s1 все еще доступен для справки!
Мы все еще можем заглянуть в s1, чтобы получить 1, тогда как в правильной реализации стека элемент 1 пропал из s1!
Что это значит?
Каждый созданный дополнительный связанный список служит ссылкой / указателем! Конечное количество стеков не может этого сделать.
Из того, что я вижу в статьях / коде, все алгоритмы используют это свойство связанных списков для сохранения ссылок.
Редактировать: я имею в виду только алгоритмы 2-го и 3-го связанных списков, использующие это свойство связанных списков, так как я их сначала прочитал (они выглядели проще). Это не означает, что они применимы или не применимы, просто чтобы объяснить, что связанные списки не обязательно идентичны. Я прочитаю один с 6, когда я свободен. @Welbog: Спасибо за исправление.
Лень также может симулировать функциональность указателя подобными способами.
Использование связанных списков решает другую проблему. Эту стратегию можно использовать для реализации очередей в реальном времени в Лиспе (или, по крайней мере, в Лиспе, который настаивает на построении всего из связанных списков): обратитесь к разделу «Операции с очередями в реальном времени в чистом Лиспе» (связан с ссылками antti.huima). Это также хороший способ создания неизменяемых списков с O (1) временем работы и общими (неизменяемыми) структурами.
источник
java.util.Stack
объекты. Единственное место, где эта функция используется, - это оптимизация, которая позволяет «дублироваться» неизменным стекам в постоянное время, чего не могут сделать базовые стеки Java (но которые могут быть реализованы в Java), поскольку они являются изменяемыми структурами.Вы можете сделать это в амортизированном постоянном времени с двумя стеками:
Добавление is
O(1)
и удаление is,O(1)
если сторона, с которой вы хотите взять, не пуста, аO(n)
иначе (разделите другой стек на две части).Хитрость заключается в том, чтобы видеть, что
O(n)
операция будет выполняться только каждыйO(n)
раз (если вы разделены, например, пополам). Следовательно, среднее время для операции составляетO(1)+O(n)/O(n) = O(1)
.Хотя это может показаться проблемой, если вы используете императивный язык со стеком на основе массива (самый быстрый), вы все равно будете иметь только амортизированное постоянное время.
источник