教育的次元
Lomutoのパーティション分割方法は単純であるため、実装が簡単になる場合があります。ソートに関するJon Bentleyのプログラミングパールには素晴らしい逸話があります。
「Quicksortのほとんどの議論では、2つの接近するインデックスに基づいたパーティションスキームを使用しています[...] [ie Hoare's]。そのスキームの基本的な考え方は簡単ですが、詳細は常に注意が必要です。2日間の大部分を短いパーティションループに隠れているバグを追いかけてきました。予備ドラフトの読者は、標準の2インデックス方式が実際にはLomutoの方式よりも簡単であると不満を述べ、彼のポイントを示すためにいくつかのコードをスケッチしました。2つのバグを見つけた後、私は探していませんでした。」
パフォーマンス次元
実際の使用では、効率のために実装の容易さが犠牲になる場合があります。理論的には、パフォーマンスを比較するための要素比較とスワップの数を決定できます。さらに、実際の実行時間は、キャッシュのパフォーマンスや分岐の予測ミスなど、他の要因の影響を受けます。
以下に示すように、アルゴリズムは、スワップの数を除き、ランダムな順列で非常によく似た動作をします。ロムトはホアレと同じ数の三倍必要です!
比較の数
両方のメソッドは、長さ配列を分割するために比較を使用して実装できます。配置場所を決定するためにすべての要素をピボットと比較する必要があるため、これは本質的に最適です。n−1n
スワップの数
スワップの数は、配列の要素に応じて、両方のアルゴリズムでランダムです。ランダムな順列、つまり、すべての要素が別個であり、要素のすべての順列が等しくなる可能性があると仮定した場合、予想されるスワップの数を分析できます。
相対的な順序カウントのみであるため、要素は数字と想定します。これにより、要素のランクとその値が一致するため、以下の説明が簡単になります。1,…,n
ロムトの方法
インデックス変数は配列全体をスキャンし、ピボットよりも小さい要素を見つけるたびにスワップを行います。要素、厳密にの要素はより小さいため、ピボットが場合はスワップが得られます。jA[j]x1,…,nx−1xx−1x
全体的な期待値は、すべてのピボットを平均することで得られます。各値は同様にピボットになる可能性が高い(つまりprob。)ので、{1,…,n}1n
1n∑x=1n(x−1)=n2−12.
Lomutoの方法で長さ配列を分割するために平均でスワップします。n
ホーアの方法
ここで、分析はもう少し複雑です。ピボット修正しても、スワップの数はランダムのままです。x
より正確に:インデックスとは、交差するまで相互に向かって実行されます。これは常に発生します(Hoareの分割アルゴリズムの正確さによる!)。これにより、配列は2つの部分に効果的に分割されます。左の部分はによってスキャンされ、右の部分はによってスキャンされます。ijxij
さて、スワップは「置き違い」の要素のペアごとに正確に行われます。すなわち、現在左部分にある大きな要素(より大きく、したがって右パーティションに属する)と右部分にある小さな要素に対して行われます。このペア形成は常に有効であることに注意してください。つまり、最初は右側の小さな要素の数が左側の大きな要素の数に等しくなります。x
一つは、これらの対の数であることを示すことができるhypergeometrically 分散のための:我々は、ランダム配列におけるそれらの位置を描画し、持っている大きな要素の位置を左の部分。したがって、ピボットが場合、予想されるペアの数はです。Hyp(n−1,n−x,x−1)n−xx−1(n−x)(x−1)/(n−1)x
最後に、すべてのピボット値を再度平均して、Hoareのパーティション分割のための全体的な予想スワップ数を取得します。
1n∑x=1n(n−x)(x−1)n−1=n6−13.
(より詳細な説明は、私の修士論文、29ページにあります。)
メモリアクセスパターン
両方のアルゴリズムは、2つのポインターを使用して、配列を順番にスキャンします。したがって、両方ともほぼ最適なwrtキャッシングを行います。
等しい要素と既にソートされたリスト
Wandering Logicで既に述べたように、アルゴリズムのパフォーマンスは、ランダムな順列ではないリストの場合により大きく異なります。
既にソートされた配列では、Hoareのメソッドは、ペアの配置ミスがないため(上記参照)、スワップしませんが、Lomutoのメソッドは、ほぼスワップを行います!n/2
等しい要素が存在するため、Quicksortでは特別な注意が必要です。(自分でこのtrapに足を踏み入れました。「早すぎる最適化の物語」については、36ページの修士論文を参照してください)極端な例として、で満たされた配列を考えてください。そのような配列では、Hoareのメソッドは要素のすべてのペアに対してスワップを実行します(これはHoareのパーティション分割の最悪のケースです)が、と常に配列の中央で一致します。したがって、最適なパーティション分割が行われ、合計実行時間はです。0ijO(nlogn)
Lomutoのメソッドは、すべて配列に対してはるかに愚かな動作をします。比較は常に真であるため、すべての要素に対してスワップを行います。さらに悪いことに、ループ後は常にであるため、最悪の場合のパーティショニングが観察され、全体のパフォーマンスが低下します!0A[j] <= x
i=nΘ(n2)
結論
Lomutoのメソッドは実装が簡単で簡単ですが、ライブラリの並べ替えメソッドの実装には使用しないでください。
A[i+1] <= x
です。ソートされた配列(および合理的に選択されたピボットが与えられた場合)では、Hoareはほとんどスワップを行わず、Lomutoは1トンを行います(jが十分に小さくなると、すべてのA[j] <= x
。)。