Deque

Mar. 24th, 2014 04:30 pm
migmit: (Default)
[personal profile] migmit
Наткнулся тут на простенькую задачку: написать стек, поддерживающий, кроме стандартных push и pop, ещё и операцию min, которая возвращает минимальное значение из содержащихся в стеке. При этом все три операции должны выполняться за O(1).

Ну, задачка действительно простая, но меня натолкнула на мысль: а что, если вместо стека делать deque, т.е., массив элементов, к которому можно добавлять новые (и удалять старые) как с левого конца, так и с правого? При этом по-прежнему хочется делать min.

Пока что у меня получилась реализация, делающая pop_front, pop_back и min за O(1), а push_back и push_front - за амортизированное O(1).

Вопрос к коллегам: это где-нибудь есть?

Date: 2014-03-24 03:58 pm (UTC)
From: [identity profile] nponeccop.livejournal.com
На случай, если Вы не знали, "штука, делающая min", называется http://en.wikipedia.org/wiki/Priority_queue

Date: 2014-03-24 04:03 pm (UTC)
From: [identity profile] antilamer.livejournal.com
PQ это скорее штука, делающая непосредственный доступ к обладателю min. В посте такого требования нет.

Date: 2014-03-24 06:38 pm (UTC)
From: [identity profile] migmit.livejournal.com
Э-э-э, не вижу особого сходства. Вроде, там и интерфейс другой (не pop_front и pop_back, а один pop_min), и временные показатели (в классической реализации) другие.

Date: 2014-03-25 02:08 pm (UTC)
From: [identity profile] nponeccop.livejournal.com
Вам нужна штука, умеющая

а) делать get_min, являющийся частным случаем pop_min
б) выполнять другие операции (pop_front и pop_back)

Очевидно, что любая priority queue умеет пункт А. Соответственно, я посоветовал полистать литературу на тему priority queue, может окажется, что некоторые варианты умеют нужные Вам операции, ну и заполучить нужные ключевые слова.

А какая это реализация priority queue выделена Вами как классическая? array-backed binary heap?

Date: 2014-03-25 06:04 pm (UTC)
From: [identity profile] migmit.livejournal.com
Очевидно, что любой стек умеет часть того, что требуется. Причём большую часть, чем priority queue. Тем не менее, стек не годится.

Кроме того, подразумеваемым обычно свойством priority queue является частичное НЕсохранение порядка, в то время как нам нужно держать порядок точно.

Короче говоря, страшно далеки они от того, что надо. Впрочем, решение с амортизированным O(1) я, как уже говорил, придумал, а ниже привели решение с настоящим O(1). И ни то, ни другое не имеет отношения к priority queue.

> array-backed binary heap?

Она, родимая.

Date: 2014-03-24 04:21 pm (UTC)
From: [identity profile] riftman.livejournal.com
На память ограничений, я так понимаю, нет?

Date: 2014-03-24 06:39 pm (UTC)
From: [identity profile] migmit.livejournal.com
Память O(n).

Date: 2014-03-24 05:43 pm (UTC)
From: [identity profile] kgeorgiy.livejournal.com
Можно сделать все операции за O(1). Для этого берем Purely Functional, Real-Time Deques with Catenation (http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.13.3451) и храним в каждом элементе структуры минимум (на самом деле, это должно работать с любым моноидом).

Если достаточно амортизированного O(1), то выкидываем идею про recursive slow-down (вместе с расскраской и счетчиками) -- и получаем, фактически, rope (http://en.wikipedia.org/wiki/Rope_(data_structure)) на основе леса полных деревьев.

Date: 2014-03-24 06:39 pm (UTC)
From: [identity profile] migmit.livejournal.com
Та-ак, вот это будем посмотреть, спасибо.

Date: 2014-03-24 07:15 pm (UTC)
From: [identity profile] migmit.livejournal.com
Клёво. Похоже, будет работать.

Date: 2014-03-24 07:39 pm (UTC)
From: [identity profile] freedom_of_sea.livejournal.com
храните min отдельно , при изменениях при необходимости обновляйте

Date: 2014-03-25 07:07 am (UTC)
From: [identity profile] freedom_of_sea.livejournal.com
было бы вежливее с вашей стороны объяснить свою позицию

Date: 2014-03-25 07:18 am (UTC)
From: [identity profile] migmit.livejournal.com
Попробуйте прикинуть, сколько времени займёт "обновление".

Date: 2014-03-25 07:25 am (UTC)
From: [identity profile] freedom_of_sea.livejournal.com
вставка в стек довольно сложная операция, обновление одной ячейки не сильно её замедлит. А поиск по всему стеку или сортировка в любом случае намного дороже

Date: 2014-03-25 07:26 am (UTC)
From: [identity profile] migmit.livejournal.com
Вопрос не в том, сколько займёт запись в одну ячейку. Вопрос в том, сколько займёт выяснение того, что туда нужно записать.

Date: 2014-03-25 08:06 am (UTC)
From: [identity profile] freedom_of_sea.livejournal.com
запись в ячейку стека нового значения ничем не отличается от обычной.
Запись в ячейку min производится только если новое значение меньше старого min

Date: 2014-03-25 09:31 am (UTC)
From: [identity profile] nealar.livejournal.com
А при удалении головы из стека?

Date: 2014-03-25 09:45 am (UTC)
From: [identity profile] freedom_of_sea.livejournal.com
ну да, точно.

проверка стоит недорого, а изменятся значение min будет редко

Date: 2014-03-25 10:05 am (UTC)
From: [identity profile] migmit.livejournal.com
Как вы думаете, сколько операций сравнения потребуется для этого "обновления", если сделать следующие операции:
push(5)
push(4)
push(3)
push(2)
push(1)
push(0)
pop()
pop()
pop()
pop()
pop()
pop()

Date: 2014-03-25 10:17 am (UTC)
From: [identity profile] freedom_of_sea.livejournal.com
все конечно зависит от величины стека и частоты запроса min. Полный поиск min по стеку (с различными выкрутасами типа индексов) намного дороже обновления min

Date: 2014-03-25 10:42 am (UTC)
From: [identity profile] migmit.livejournal.com
Ужасы какие рассказываете.

По-нормальному нужно просто держать два стека, один обычный, а другой состоящий из тех элементов первого, глубже которых нет ни одного элемента меньше. Будет O(1) на push, pop и min.

Date: 2014-03-25 10:56 am (UTC)
From: [identity profile] kgeorgiy.livejournal.com
Можно еще проще -- хранить в стеке пары (элемент, соответствующий минимум).

Date: 2014-03-25 11:21 am (UTC)
From: [identity profile] migmit.livejournal.com
Или так, да.

Date: 2014-03-25 11:58 am (UTC)
From: [identity profile] nealar.livejournal.com
Таки да! Если всё равно O(2N) память, то зачем извращаться.

Date: 2014-03-25 12:04 pm (UTC)
From: [identity profile] migmit.livejournal.com
O(N), в общем-то, от O(N) ничем не отличается.

Date: 2014-03-25 12:27 pm (UTC)
From: [identity profile] nealar.livejournal.com
Я как бы в курсе.

Date: 2014-03-25 06:05 pm (UTC)
From: [identity profile] migmit.livejournal.com
Блин. Я, оказывается, пропустил 2.

Я не сомневаюсь, что в курсе, но людей, на голубом глазу утверждавших, что O(2N) и O(N) — разные вещи, я видел.

Date: 2014-03-25 06:29 pm (UTC)
From: [identity profile] nealar.livejournal.com
Я, оказывается, пропустил 2.
Я решил, что это такая подколка. Ведь так в итоге и получается.

утверждавших, что O(2N) и O(N) — разные вещи
Уже интересно, что они говорили за O(N+1).