読み取り専用スタックを使用した並べ替え


14

次の設定を考慮してください。

  • 我々は、スタック与えられている含まれているn個のアイテムを。sn
  • 一定の数の追加スタックを使用できます。O(1)
  • これらのスタックに次の操作を適用できます。
    1. スタックが空かどうかを確認し、
    2. 2つのスタックの一番上のアイテムを比較し、
    3. スタックの一番上のアイテムを削除し、
    4. スタックの一番上のアイテムを印刷し、
    5. スタックの一番上のアイテムを別のスタックにコピーし、
    6. あるスタックのコンテンツを別のスタックにコピーします。

許可される操作はこれらのみであることに注意してください。アイテムを交換することはできず、スタックにアイテムをコピーすることを除き、スタックにアイテムをプッシュすることはできません(その後、ターゲットスタックの以前のコンテンツは破棄され、コピーされたアイテムのみが含まれます) 。

比較でスタックをソートするアルゴリズムは次のとおりです。O(n2)

last := empty
for i from 1 to n
  min := empty
  w := s
  while w is not empty
    if w.top > last and w.top < min
      min := w.top
    delete w.top
  print min
  last := min

もっと良くできますか?

比較のみを使用してスタック内のアイテムのソートされたリストを印刷するプログラムはありますか?O(nログ⁡n)


2
レジスタはスタックのように動作するように聞こえますか?プッシュ操作とポップ操作について話しているようです。それはあなたの質問ですか?複数のスタックとスタック操作を使用して、スタックをどのようにソートしますか?
— wolfdawn 14

2
ではのレジスタ次のことができます。ちょうど1つのレジスタ(内のすべての番号を入れてO (N ))、その後、通常のソートアルゴリズム(適用O (nはLG のnを))。nO(n)O(nlg⁡n)
— カベ14

1
レジスタを使用しますか?そうでなければ、Kavehがコメントしたように、問題は平凡になります。O(1)
— ユヴァルフィルマス14

1
どういたしまして。1つだけではなく、多くのスタックが与えられると思いました。それを修正します。
— カベ14

2
@akappa、あなたはこの見物でそれを使うことができると確信していますか?1を超えるサイズの任意の損失を保持することはできません。ソートされたブロックを保存する必要はありませんか?
— カベ14

回答:


1

今、自明でない下限を示すことができると思います。そのようなプログラムは、比較分岐プログラムのファミリで実装するという考え方です。「読み取り専用」の仮定は、分岐プログラムのファミリーがほとんど、つまりスペースを使用しないことを意味します。次に、ボロディンらによって証明された下限S T = Ω (n 2)を適用します。「気づかないマシンでソートするための時間と空間のトレードオフ」。これにより、時間のn 2 / log nの下限が得られます。O(log⁡n)ST=Ω(n2)n2/log⁡n

もう少し詳しく:上記の操作5は不要です。大まかに言って、2つのリストのヘッドを既に比較してリストのヘッドを印刷できる場合、特定のレジスタでリストのヘッドを分離する必要はありません。これを仮定すると、マシンのすべてのレジスターは入力の最終部分文字列のみを保存することがわかります。

レジスタプログラムに行のコードとk個のレジスタX 1、… 、X kがあるとします。ℓkX1,…,Xk

修正します。次のように、長さnの文字列に対して比較分岐プログラムを構築します。各タプルのノードの作成(I 、D 1、... 、D K)1 ≤ I ≤ ℓ と0 ≤ D 1、... 、D K ≤ N。考え方は、レジスタマシンでの計算は分岐プログラムのパスに対応し、ノード(i 、d 1、… 、dnn(i,d1,…,dk)1≤i≤ℓ0≤d1,…,dk≤nレジスタマシンの行 iにあり、 X iに格納されている文字列の長さが d iである場合。次に、分岐プログラムの有向エッジを定義する必要があります(i,d1,…,dk)私バツ私d私

行が次の形式の場合私

場合はi 1に移動し、そうでない場合はi 2に移動しますバツあなたは<バツv私1私2

次に、すべての、ノード(i 、d 1、… 、d k)は、入力のd u番目とd v番目の要素を比較し、「true」エッジを(i 1、d 1、… 、d kd1、…、dk(私、d1、…、dk)dあなたはdv、および( false)エッジから(i 2、d 1、… 、d k(私1、d1、…、dk)。(私2、d1、…、dk)

行が次の形式の場合私

、ライン後藤 I 'バツ1←ta私l(バツ2)私′

次に、任意のノードから(i ′(私、d1、…、dk)。(私′、d2−1、…、dk)

行が次の形式の場合私

、後藤ライン I 'pr私nt(head(バツあなたは))私′

次に、任意のノードから(i ′、d 1(私、d1、…、dk)、入力の d u番目のノードによってラベル付けされています。(私′、d1、…、dk)dあなたは

これらの例が、分岐プログラムをどのように構築するつもりであるかを明確にしたいです。すべての作業を完了すると、この分岐プログラムは、最大でありℓ⋅nkが持つように、ノードの空間O(ログ⁡n)


0

要素を数えることができますか?次に、Mergesortの実装はかなり簡単だと思います。スタックに追加のシンボルを配置できた場合、次のような3つのスタックで解決できます。

要素が1つしかない場合、リストは既にソートされています。ここで、スタックの上半分がすでにソートされていると仮定します。上半分を(逆順で)2番目のスタックにコピーし、その上に分離記号を配置できます。これで、3つのスタックができました(分離記号の下の既にソートされた記号を無視できるため)。下半分をソートできます。最後に、ソートされた下半分を逆の順序で3番目のスタックにコピーし、両方の半分を元のスタックにマージします。

すべての操作は線形時間を要するため、O(nログ⁡n)

(注:サイズのスタックが必要です 分離記号のため n log nのが、これは別のスタックを使用して簡単に修正できます)nログ⁡n


スタックに新しい要素を配置できないため、分離点で問題が発生する可能性があります。これを解決するには、追加のスタックを使用して次の操作を実行します。

トップコピー追加スタックに要素を、次に前と残りの要素を進めます。これで、各ステップで考慮する必要がある要素の数が正確にわかったため、分離記号は必要ありません。n−2⌊ログ⁡n⌋

最後に追加の要素を最大回使用して手順を繰り返し、線形時間で元のスタックにマージします。スタックを並べ替えるには、いくつかの定数cに対して、最大でc n log n +ログ⁡nccnログ⁡n+cn2ログ⁡n2+cn4ログ⁡n4+ 。。。=O(nログ⁡n)O(nログ⁡n)


私は上手く理解できていない気がします。たとえば、スタックに要素をプッシュできない場合に、スタックの上半分を逆の順序で別のスタックにコピーするにはどうすればよいですか?
— シッダールト14

新しい要素をスタックにプッシュすることはできませんが、5によれば、あるスタックの最上位の要素を別のスタックにプッシュできます。したがって、スタックを逆順でコピーするには、せいぜい線形の時間が必要です。だから、それはあなたが求めていたものではなかったと思う?
— セロ14

質問で説明されているように、他のアイテムの上に何かをプッシュすることはできません。
— カベ14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.