web-dev-qa-db-ja.com

クイックソートとミドルピボット

ミドルピボットでクイックソートを理解していると頭痛がします。左端または右端を使用することについて多くの説明が見つかりましたが、中央の説明については多くありませんでした。

これらを安全に想定できますか?:

  1. 左と右のポインターが同じ位置で出会う場合、その位置の要素はその最終的なソート位置にあることを意味するので、その要素を含めずにリストを2つに分割できます(list1 length + list2 length = list length -1)。

  2. 左と右が交差している場合(つまり、左>右)、最終的なソート位置に要素がないため、左と右を境界として使用してリストを2つに分割する必要があります(リスト1の長さ+リスト2の長さ=リストの長さ) 。

これは正解?

ありがとう。

Update:中央のピボットを使用する理由は、QS速度を向上させる「中央値アルゴリズム」を実装するためです。この手法では、ピボットはリストの中央値を概算することによって選択されます。 http://www.brpreiss.com/books/opus4/html/page500.html

1
NullOrEmpty

配列がランダムにシャッフルされている場合、理論的には、リスト内の1つの項目は別の項目と同じように優れています。つまり、最も都合のよいものを選択できます。ただし、配列がalmostでソートされている場合(またはクイックソートでO(n ^ 2)時間がかかる場合)は、中間のアイテムの方が適していると言えます。中間のアイテムを取るのは、この場合は半分が少なく半分が多いアイテムの代表である可能性が高いためです。ランダムである場合、それ以外の点ではそれほど違いはないでしょうか。

この例のために、配列がランダムにシャッフルされていると仮定して、リストの右端の項目をピボットとして任意に名前を付けます。左から、その数をピボットと比較します。数値がピボットより小さい場合は、次の数値に進みます。数値がピボットより大きい場合は、次のようにします。

ピボットが現在の番号に隣接していない場合、ピボットは左隣のピボットに切り替わります。次に、現在の番号が、新しいピボットの右側に作成された新しいスロットと入れ替わります。ピボットが現在の番号に隣接している場合は、現在の番号で位置を切り替えるだけです。

現在の番号のインデックスがピボットのインデックス以上になるまで、これらの手順を続けます。これが完了したら、ピボットの左側にあるすべてのサブリストへの再帰呼び出しと、ピボットの右側にあるすべてのサブリストへの別の呼び出しを実行します(サブリストの長さが2以上であると想定)。

例を見てみましょう:

1 4 8 9 2 3 5

5がピボットです。インデックス0から始めて、次の操作を取得します。

1 4 8 9 2 3 5
^           *
1 4 8 9 2 3 5
  ^         *
1 4 3 9 2 5 8
    ^     *
1 4 3 9 2 5 8
    ^     *
1 4 3 2 5 9 8
      ^ * 
1 4 3 2 5 9 8
      ^ * 

最初のパスの終わり:左側のサブリストへの再帰呼び出し:

1 4 3 2 
^     *
1 3 2 4 
  ^ *  
1 2 3 4 
  ^ *  

そして、右側のサブリストへの再帰呼び出し:

9 8  
^ *
8 9  
* ^

分かりやすくなるといいですね。現在の数がピボットより大きい場合、現在の数が増加しなかったことに注意してください。これは、まだ処理されていない別の番号に置き換えられるため、確認する必要があるためです。あなたがミドルピボットでやっていたことは正確ではないことは知っていますが、これも同様に機能します。

0
Neil