クイックソートを理解するのに苦労しています。ほとんどのデモンストレーションと説明では、実際に何が起こっているのかを省略しています( http://me.dt.in.th/page/Quicksort/ など)。
ウィキペディアによると:
配列からピボットと呼ばれる要素を選択します。パーティショニング:ピボットよりも小さい値を持つすべての要素がピボットの前に来るように配列を並べ替え、ピボットよりも大きい値を持つすべての要素がピボットの後に来るようにします(等しい値はどちらの方向にも行くことができます)。この分割の後、ピボットは最終的な位置になります。これをパーティション操作と呼びます。上記の手順を、値が小さい要素のサブ配列に再帰的に適用し、値が大きい要素のサブ配列に個別に適用します。
たとえば7をピボットとして、9,1,7,8,8の配列でどのように機能しますか? 9はピボットの右側に移動する必要があります。すべてのクイックソートの実装は適切な操作であるため、8、8の後に追加することはできません。したがって、唯一のオプションは9を7と交換することです。
これで、配列は7,1,9,8,8になります。クイックソートの背後にある考え方は、ピボットの左右にパーツを再帰的にソートする必要があるということです。ピボットは配列の位置0にあります。つまり、左側の部分がないため、右側の部分のみを並べ替えることができます。これは7> 1としては役に立たないため、ピボットが間違った場所に配置されてしまいました。
この画像では4がピボットですが、なぜ5がほぼ左に移動しているのでしょうか。 4より大きいです!何度も交換した後、ソートされてしまいますが、それがどのように起こったのかわかりません。
クイックソートの手順は次のとおりです。
Lomutoパーティションスキーム
パーティションアルゴリズム(Lomutoパーティションスキームを使用)
algorithm partition(A, lo, hi) is
pivot := A[hi]
i := lo // place for swapping
for j := lo to hi – 1 do
if A[j] ≤ pivot then
swap A[i] with A[j]
i := i + 1
swap A[i] with A[hi]
return i
クイックソートアルゴリズム(Lomutoパーティションスキームを使用)
algorithm quicksort(A, lo, hi) is
if lo < hi then
p := partition(A, lo, hi)
quicksort(A, lo, p – 1)
quicksort(A, p + 1, hi)
Hoareパーティションスキーム
パーティション化されている配列の端から始まり、反転が検出されるまで互いに向かって移動する2つのインデックスを使用します。1つはピボットより大きく、もう1つは小さい要素のペアで、互いに対して順序が間違っています。 。次に、反転された要素が交換されます。
このアルゴリズムには多くのバリアントがあります。たとえば、A [hi]の代わりにピボットを選択します。 A [lo]
パーティションアルゴリズム(Hoareパーティションスキームを使用)
algorithm partition(A, lo, hi) is
pivot := A[lo]
i := lo – 1
j := hi + 1
loop forever
do
i := i + 1
while A[i] < pivot
do
j := j – 1
while A[j] > pivot
if i >= j then
return j
swap A[i] with A[j]
クイックソートアルゴリズム(Hoareパーティションスキームを使用)
algorithm quicksort(A, lo, hi) is
if lo < hi then
p := partition(A, lo, hi)
quicksort(A, lo, p)
quicksort(A, p + 1, hi)
HoareパーティションスキームとLomutoパーティションスキーム
ピボットの選択
アルゴリズムの実行速度は、このメカニズムの実装方法に大きく依存します。実装が不十分な場合、アルゴリズムが低速で実行されていると見なされる可能性があります。
ピボットの選択により、データリストのパーティションが決まります。したがって、これはクイックソートアルゴリズムの実装の最も重要な部分です。 ピボットの左右のパーティションの選択が可能な限り同じサイズになるようにすることが重要です。
ベストケースとワーストケース
最悪の場合
最も不均衡なパーティションは、ピボットがリストをサイズ_0とn − 1の2つのサブリストに分割するときに発生します。これは、ピボットがリスト内の最小または最大の要素である場合、またはすべての要素が等しい場合の一部の実装で発生する可能性があります。
ベストケース最もバランスの取れたケースでは、パーティションを実行するたびに、リストを2つのほぼ等しい部分に分割します。これは、各再帰呼び出しが半分のサイズのリストを処理することを意味します。
正式な分析
例 ソース
追加メモリの使用
def quicksort(array):
less = []
equal = []
greater = []
if len(array) > 1:
pivot = array[0]
for x in array:
if x < pivot:
less.append(x)
if x == pivot:
equal.append(x)
if x > pivot:
greater.append(x)
return sort(less)+equal+sort(greater)
else:
return array
使用法:
quicksort([12,4,5,6,7,3,1,15])
追加メモリなし
def partition(array, begin, end):
pivot = begin
for i in xrange(begin+1, end+1):
if array[i] <= array[begin]:
pivot += 1
array[i], array[pivot] = array[pivot], array[i]
array[pivot], array[begin] = array[begin], array[pivot]
return pivot
def quicksort(array, begin=0, end=None):
if end is None:
end = len(array) - 1
if begin >= end:
return
pivot = partition(array, begin, end)
quicksort(array, begin, pivot-1)
quicksort(array, pivot+1, end)
使用法:
quicksort([97, 200, 100, 101, 211, 107])
あなたの例では
Lomutoパーティションのデバッグ
ある日、私はこの宝石を見つけました。これは、さまざまなアニメーションを作成します ソートアルゴリズム これは、それらを理解するのに大いに役立ちました!しかし、これは単なるグラフィカルな説明であり、私の前のポスター(@Hydex)は、すでに学術的な方法で回答されています;-)