2つのキューを使用したリストの反転


12

この質問は、スタック操作ごとに償却時間で2つのキューを使用してスタックをシミュレートできるかどうかに関する既存の質問に触発されています。答えは不明のようです。以下に、より具体的な質問を示します。これは、すべてのPUSH操作が最初に実行され、次にすべてのPOP操作が実行される特殊なケースに対応しています。最初に空の2つのキューを使用して、要素のリストをどれだけ効率的に逆にすることができますか?法的操作は次のとおりです。O(1)N

  1. 入力リストの次の要素をキューに入れます(どちらかのキューの末尾に)。
  2. どちらかのキューの先頭にある要素をデキューし、再度(いずれかのキューの末尾に)エンキューします。
  3. いずれかのキューの先頭にある要素をデキューし、出力リストに追加します。

入力リストが要素で構成されている場合、逆の出力リスト[N、N-1、...、2、 1]振る舞いますか?O(N)よりも速く成長するという証明は、元の質問を否定的に解決するため、特に興味深いでしょう。[1,2,...,N1,N][N,N1,...,2,1]O(N)


更新(2011年1月15日):提出された回答とそのコメントに示されているように、問題はO(NlogN)で解決できます。\ Omega(N)の下限Ω(N)は自明です。これらの境界のいずれかを改善できますか?


明確にするために:「どちらかのキューの最後の要素」とは、キューの先頭にある要素を指しますか?
ピーターテイラー

@ピーター:はい、説明してくれてありがとう。質問を編集しました。
mjqxxxx

入力リストと出力リストの両方がスタックしていますか?もしそうなら、n op1s(同じキューへ)に続いてn op3sは逆になりますか?私は重要な何かを見逃しているに違いないと思う。
jbapple

@jbapple:いいえ、スタックではありません。入力リストから読み取られた順序と逆の順序で要素を出力リストに書き込む必要があります。
mjqxxxx

回答:


11

Nが2のべき乗である場合、すべてのアイテムがいずれかのキューで開始され、いずれかのキューで逆順で終了する必要がある、より制限された問題でも、O(N log N)操作で十分であると思います(入力および出力リスト)。

O(N)ステップでは、1つのキューのすべての要素から開始し、「one for you one for me」を再生して他のキューの代替サブセットに分割し、それらをすべて1つのキューに連結して戻すことができます。アイテムの位置のバイナリ表現に関して、これは回転操作を実装します。

O(N)ステップでは、1つのキューから要素のペアを取り出し、それらを交換してから元に戻し、すべてのペアを逆にすることもできます。アイテムの位置のバイナリ表現に関して、これは位置の下位ビットを補完します。

O(log N)回アンシャッフルとペアワイズスワップを繰り返すことで、位置のバイナリ表現のすべてのビットを補完できます。これはリストを逆にするのと同じことです。


次に、リストをバイナリ表現に分解し、O(n lg n)アルゴリズムのピースごとに逆にすることができると思います。
jbapple

バイナリの代わりに2-3ツリーを使用することで、すべてのNに拡張できると考えていましたが、おそらくあなたの考えはより単純です。しかし、O(n log n)の合計ステップでO(log n)の各部分をどのように反転させるのでしょうか?
デビッドエップシュタイン

時間はO(sum(2 ^ i)lg(2 ^ i))であり、0から[lg n]までのiに対して、Wolfram alphaはO(n lg n)と言います:wolframalpha.com/input/?i=sum+ (2 ^ k)+ log2 +(2 ^ k)+ from + 0 + to + log2 + n
jbapple

確かに、その長さをそのログに掛けた時間に比例して時間の各部分を逆にすることができれば、完了です。しかし、いったんピースを反転したら、ピースをどこかに配置する必要があります。そうすると、残りのピースを反転するのが難しくなります。
デビッドエップシュタイン

この問題は「出力リスト」を想定しています。そこに置いてもいいですか?
jbapple

1

i=0N/21(N2i2)

使用可能な2つのキューに左右の名前を付けましょう。Nが偶数であるという仮定のもとで、このアルゴリズムの基本的な考え方を以下に示します。

  1. 要素の初期リストから値を読み取り、すべての奇数を左のキューに入れ、偶数を右のキューに入れます
  2. 最大値を出力する最速の方法の1つは、N / 2-1要素を右のキューから左のキューに転送し、右のキューから出力リストに上の値をポップすることです。
  3. 次に、別のキューに対して同じことを行う必要があります-N / 2-1要素を左のキューから右のキューに転送し、左のキューから出力リストに上の要素をポップします
  4. キューを交換し、N = N-2で手順2と3を繰り返します

アルゴリズムが奇数Nに対してどのように機能するかを簡単に確認できます。


$ ... $を使用して、LaTeX風のコード(\を除く)を挿入できます。
マークライトブラット
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.