web-dev-qa-db-ja.com

クイックソートを理解する

クイックソートを理解するのに苦労しています。ほとんどのデモンストレーションと説明では、実際に何が起こっているのかを省略しています( 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より大きいです!何度も交換した後、ソートされてしまいますが、それがどのように起こったのかわかりません。

https://upload.wikimedia.org/wikipedia/commons/thumb/a/af/Quicksort-diagram.svg/400px-Quicksort-diagram.svg.png

12
Plumpie

クイックソート

クイックソートの手順は次のとおりです。

  • リストからピボットと呼ばれる要素を選択します。
  • ピボットよりも小さい値を持つすべての要素がピボットの前に来るようにリストを並べ替え、ピボットよりも大きい値を持つすべての要素がピボットの後に来るようにします(等しい値はどちらの方向にも行くことができます)。この分割の後、ピボットは最終的な位置になります。これはパーティション操作と呼ばれます。
  • 小さい要素のサブリストと大きい要素のサブリストを再帰的に並べ替えます。再帰の基本ケースは、サイズが0または1のリストであり、ソートする必要はありません。

Lomutoパーティションスキーム

  • このスキームは、通常、配列の最後の要素であるピボットを選択します。
  • アルゴリズムは、ピボットを変数iに配置するためのインデックスを維持し、ピボット以下の要素が見つかるたびに、このインデックスがインクリメントされ、その要素がピボットの前に配置されます。
  • このスキームはよりコンパクトで理解しやすいため、入門資料で頻繁に使用されます。
  • Hoareの元のスキームよりも効率が低くなります。

パーティションアルゴリズム(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つのサブリストに分割するときに発生します。これは、ピボットがリスト内の最小または最大の要素である場合、またはすべての要素が等しい場合の一部の実装で発生する可能性があります。

Imgur

ベストケース最もバランスの取れたケースでは、パーティションを実行するたびに、リストを2つのほぼ等しい部分に分割します。これは、各再帰呼び出しが半分のサイズのリストを処理することを意味します。

Imgur

正式な分析

  • 最悪の場合の分析=O(n²)
  • 最良の分析=O(n)係数
  • 平均ケース分析=O(n log n)

ソース

追加メモリの使用

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])

あなたの例では Imgur

Lomutoパーティションのデバッグ Imgur

19
Hydex

ある日、私はこの宝石を見つけました。これは、さまざまなアニメーションを作成します ソートアルゴリズム これは、それらを理解するのに大いに役立ちました!しかし、これは単なるグラフィカルな説明であり、私の前のポスター(@Hydex)は、すでに学術的な方法で回答されています;-)

0