O(1)プッシュ/ポップ時間を使用して、3つのスタックを1つのアレイに実装できますか?


9

2つのスタックは、1つの固定サイズの配列を使用して効率的に実装できます。スタック#1は左端から始まり、右に向かって成長し、スタック#2は右端から始まり、左に向かって成長します。3つのスタックで同じことは可能ですか?

より具体的には、次の条件を前提として、3つのスタックを実装することは可能ですか?

  1. N個のオブジェクトを保持できる固定サイズの配列があります。
  2. 3つのスタックサイズの合計が<Nである限り、push()は失敗しません。
  3. push()とpop()の両方の操作にO(1)時間かかるはずです。
  4. 配列に加えて、O(1)の追加スペースのみを使用できます。

これらの要件を満たさないソリューションの例を次に示します。

  • 配列を3つの固定部分に分割し、各部分をスタックに使用する(違反2)。
  • 上記と同様ですが、スタック間の境界が移動可能です(違反3)。
  • 単純なリンクリストベースの実装(違反4)。

それらがすべての条件(1)〜(4)を正確に満たしていない場合でも、自明ではないアルゴリズムまたは不可能性の証明を受け入れます。たとえば、プッシュ/ポップがO(1)の償却時間をとるアルゴリズム、または追加メモリはO(N)よりも小さい(例:O(log N))。または、たとえば、プッシュ/ポップごとに配列の5未満の要素にアクセスすることは不可能であることを示す不可能性の証明。


1
これを要件4の違反と見なすかどうかはわかりませんが、Nオブジェクト配列の各「オブジェクト」に整数インデックスなどの追加フィールドを含めることができる場合は、配列内に「リンクリスト」を実装できます。3つの外部変数を使用して、3つのスタックそれぞれの先頭のインデックスを保持できます。各「オブジェクト」は、そのスタックの前の要素を指すことができます。
Avi Tal

「オブジェクト」とは、push()が受け入れ、pop()が返すものを意味します。スタック実装の観点からは、これらはデータの不透明なblobです(たとえば、オブジェクトは32ビット整数である可能性があります)。スタック実装は、これらのオブジェクトを変更するべきではありません。
user1020406

1
N

ON

ON

回答:


6

ΘεΘ


0

Nを配下の配列の長さとする。スタックは大きなチャンクのリンクされたリストと考えることができるので、チャンクの総数はO(log2(N))以下になります。N / 2のインデックスで、最初の2つの間に3番目のスタックを配置します。したがって、3つの占有領域と2つの空き領域があります。スタックが次の要素を受け入れることができない場合、これは1つの空き領域が使い果たされたことを意味します。他のメモリも使い果たされると、メモリ全体が使い果たされます。それ以外の場合、サイズがN / 2以下の別の空き領域があります。オーバーフローしたスタックをその空き領域に継続します。構成全体がスタックの初期レイアウトに似ているようにします。現在、空きメモリは初期の半分以下であるため、そのようなリンク操作のlog2(N)以下になります。各リンク操作では、スタックの以前の状態を保存するために固定量のメモリが必要です。そう、


1
大きなチャンクの1つから取り出したメモリをどのようにリサイクルしますか?
EmilJeřábek19年

良い質問。簡単に言えば、解放されたチャンクは、以前に取得された空き領域にメモリを戻します。しかし、そのチャンクにメモリを割り当てたときから空き領域が減少し、チャンクが隣接していない場合はどうなりますか?これは空きメモリの断片化につながり、2つ以上の空き領域が存在する可能性があり、それが私のすべての構築を台無しにします。
Alexei Kaigorodov

ポップは確かにここでの問題ですが、アレクセイの構造は、ドミトリがコメントで尋ねた問題のバージョンの優れた上限を提供します。すべてのポップの前にすべてのプッシュを実行する必要がある場合はどうなりますか?この場合、O(log N)より良いものが可能かどうか疑問に思います。
user1020406
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.