Чи можна реалізувати три стеки в одному масиві, з O (1) час push / pop?


9

Два стеки можна ефективно реалізувати за допомогою одного масиву фіксованого розміру: стек №1 починається з лівого кінця і росте вправо, а стек №2 починається з правого кінця і росте з лівого. Чи те ж саме можливо для трьох стеків?

Більш конкретно, чи можливо реалізувати три стеки за таких умов:

  1. У вас є масив фіксованого розміру, який може містити N об’єктів.
  2. Поки сума трьох розмірів стека <N, push () не повинно провалюватися.
  3. І операції push (), і pop () повинні зайняти O (1) час.
  4. Крім масиву, ви можете використовувати лише додатковий простір O (1).

Ось приклади рішень, які не відповідають цим вимогам:

  • Розбиття масиву на 3 нерухомі частини та використання кожної частини для стека (порушує 2).
  • Аналогічно вище, але з рухомими межами між стеками (порушує 3).
  • Прості реалізації на основі пов'язаного списку (порушує 4).

Я прийму нетривіальні алгоритми чи докази неможливості, навіть якщо вони точно не відповідають усім умовам (1) - (4), наприклад, алгоритм, коли push / pop займає O (1) амортизований час, або де додаткова пам'ять менша, ніж O (N), наприклад O (log N). Або доказ неможливості, який показує, що, наприклад, отримати доступ до менш ніж 5 елементів масиву за один натискання / поп неможливо.


1
Я не знаю, чи розглядаєте ви це як порушення вимоги 4, але якщо кожен "об'єкт" у вашому масиві N об'єктів може включати додаткове поле, таке як цілий індекс, то ви можете реалізувати "пов'язані списки" у своєму масиві . Ви можете утримувати індекс у верхній частині кожного з 3 стеків за допомогою 3 зовнішніх змінних, і кожен "об'єкт" може вказувати на попередній елемент його стек.
Аві Тал

Під "об'єктами" я мав на увазі речі, які push () приймає, а pop () повертає. З точки зору реалізації стека, вони є лише непрозорими фрагментами даних (наприклад, об'єкт може бути 32-бітним цілим числом). Реалізація стека не повинна жодним чином змінювати ці об'єкти.
користувач1020406

1
Розглянемо, що спочатку виконайте послідовність натискань, а потім лише поп-операції. Чи відомо щось про цю версію проблеми? N
Дмитро Урбанович

Чи задовольнив би вас додатковий простір? O(N)
Дмитро Урбанович

Re: "N натискань, а потім N спливає" версія: Я не знаю, але навіть визначити це цікавою підпроблемою корисно, оскільки навіть там не ясно, чи можливе рішення O (1). Дивіться відповідь @ Олексія та його нитку коментарів для верхньої межі. Що стосується рішення , так, я прийму. Я новачок, коли розміщую питання на stackexchange, тому не знаю, як впоратися з випадками, коли з часом можна надати кращі та кращі рішення. Я бачив один підхід - почекати день або близько того, перш ніж приймати відповідь у випадку, якщо буде розміщено щось краще, тож я це зроблю. O(N)
користувач1020406

Відповіді:


6

Фредман і Голдсміт показали у "Три стеки" (Journal of Algorithms, 1994), що біти марно витраченого простору досяжні. Він також є мінімальним, необхідним для масивів розміром принаймні 16 квадратних мільйонів йотабайт. Я описав простий алгоритм атрофію слова простору в моєму StackOverflow відповідь на це питання . Як зазначає @ dmitri-urbanowicz в коментарях, це в основному просто трактує масив як блоки розміру , де кожен блок використовується для точно одного стека і містить один вказівник на наступний блок в тій стеці.Θ(nε)Θ(n) nn


0

Нехай N - довжина нижнього масиву. Я можу уявити стеки як зв'язані списки великих фрагментів, так що загальна кількість шматів не більше O (log2 (N)). Третій стек розмістіть між першими двома, в індексі N / 2. Отже, у нас є 3 окуповані райони та 2 вільних. Якщо стек не може прийняти наступний елемент, це означає, що одна вільна область вичерпана. Якщо інший теж вичерпаний, то вичерпується вся пам’ять. В іншому випадку є ще одна вільна площа розміром не більше N / 2. Продовжте переповнений стек у цю вільну область. так що вся конфігурація нагадує початкову компоновку стеків. Оскільки вільна пам'ять зараз становить не більше половини початкової, таких операцій зв’язку буде не більше log2 (N). Кожна операція з'єднання вимагає фіксованого обсягу пам'яті для збереження попереднього стану стека. Тому,


1
Як ви переробляєте пам’ять, отриману, вискакуючи речі з одного з великих фрагментів?
Еміль Єржабек

Хороше питання. Швидка відповідь полягає в тому, що шматок, який стає вільним, повертає свою пам'ять у вільну область, звідки вона була взята раніше. Але що робити, якщо вільна площа зменшилася з моменту виділення пам’яті для цього фрагменту, і шматок тепер не суміжний з нею? Це призводить до фрагментації вільної пам'яті, може бути більше 2 вільних областей, що руйнує всю мою конструкцію.
Олексій Кайгородов

Тут є насправді проблема, але конструкція Олексія дає гарну верхню межу для версії проблеми, про яку Дмитро запитував у коментарях: а що, якщо ми вимагатимемо, щоб усі поштовхи сталися перед усіма попсами? Цікаво, чи можливо в цьому випадку щось краще, ніж O (log N).
користувач1020406
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.