主にソートされたデータに対してどのソートアルゴリズムが最も効果的ですか?
主にソートされたデータに対してどのソートアルゴリズムが最も効果的ですか?
回答:
アニメーションgifを見る非常に科学的な方法に基づいて、挿入とバブルの並べ替えは良い候補だと思います。
少数のアイテムのみ=> INSERTION SORT
アイテムはほとんどソート済みです=>挿入ソート
最悪のシナリオが懸念される=> HEAP SORT
良い平均ケースの結果に興味がある=> QUICKSORT
アイテムは密な宇宙から描画されます=>バケットソート
できるだけ少ないコードを書くことを望んでいる=>挿入ソート
Timsortは「適応的で安定した自然なマージソート」であり、「部分的に順序付けられた多くの種類の配列で超自然的なパフォーマンスを発揮します」(lg(N!)未満の比較が必要で、N-1程度)の」を備えています。Pythonの組み込みsort()
このアルゴリズムをしばらく使用してきましたが、明らかに良い結果が得られています。これは、実際のデータセットで頻繁に発生する、入力内の部分的にソートされたサブシーケンスを検出して利用するように特別に設計されています。通常、ポインタを交換するだけなので、比較はリスト内のアイテムを交換するよりもはるかにコストがかかります。これにより、timsortが優れた選択肢になることがよくあります。ただし、比較が常に非常に安価であることを知っている場合(たとえば、32ビット整数をソートするおもちゃのプログラムを作成するなど)、パフォーマンスが向上する可能性が高い他のアルゴリズムが存在します。もちろん、timsortを利用する最も簡単な方法はPythonを使用することですが、Pythonはオープンソースであるため、コードを借用することもできます。または、上記の説明には、独自の実装を作成するのに十分な詳細が含まれています。
lg(n!)
、ほぼソートされた配列での比較よりもずっと高速O(n)
です。| @behrooz:いいえ比較ソートはより良いの平均的なケースを持つことができるO(n log n)
、とlg(n!)
ありますO(n log n)
。したがって、timsortの最悪のケースは、他の比較ソートのそれよりも漸近的に悪くはありません。さらに、その最良のケースは、他の比較ソートと同等かそれ以上です。
次の動作の挿入ソート:
k
スロットの各要素について1..n
、最初に次のことを確認しel[k] >= el[k-1]
ます。その場合は、次の要素に進みます。(明らかに最初の要素をスキップします。)1..k-1
て挿入位置を決定し、要素をスクートします。(これは、k>T
どこT
かにしきい値がある場合にのみ行う可能性があります。小さい場合、k
これはやりすぎです。)このメソッドは、比較の数が最小になります。
内省的なソートを試してください。http://en.wikipedia.org/wiki/Introsort
これはクイックソートに基づいていますが、ほぼソートされたリストに対してクイックソートが持つ最悪の場合の動作を回避します。
トリックは、このソートアルゴリズムが、クイックソートがワーストケースモードに入り、ヒープまたはマージソートに切り替わるケースを検出することです。ほぼソートされたパーティションは、いくつかの非ナイーブパーティションメソッドによって検出され、小さなパーティションは挿入ソートを使用して処理されます。
より多くのコードと複雑さのコストで、すべての主要なソートアルゴリズムの中で最高のものを手に入れます。また、データがどのように見えても、最悪の場合の動作に決して遭遇しないと確信できます。
C ++プログラマーの場合は、std :: sortアルゴリズムを確認してください。内部で内省ソートをすでに使用している可能性があります。
Splaysortは、に基づいて曖昧ソーティング方法であるスプレー木、適応的バイナリツリーのタイプ。スプレイソートは、部分的にソートされたデータだけでなく、部分的に逆ソートされたデータ、または実際に何らかの種類の既存の順序を持つデータにも適しています。一般的な場合はO(nlogn)、データが何らかの方法(順方向、逆方向、オルガンパイプなど)で並べ替えられている場合はO(n)です。
挿入ソートよりも優れている点は、データがまったくソートされていない場合にO(n ^ 2)の動作に戻らないため、データを使用する前にデータが部分的にソートされていることを完全に確認する必要はありません。 。
その不利な点は、必要なスプレイツリー構造の余分なスペースオーバーヘッド、およびスプレイツリーの構築と破棄に必要な時間です。ただし、予想されるデータのサイズと事前ソートの量によっては、速度の向上のためにオーバーヘッドが価値がある場合があります。
splaysortの論文が実践&経験-ソフトウェアに掲載されました。
ダイクストラのスムースソートは、すでにソートされたデータに対して優れたソートです。これは、O(n lg n)ワーストケースとO(n)ベストケースで実行されるヒープソートバリアントです。あなたがそれがどのように機能するか知りたければ、私はアルゴリズムの分析を書きました。
自然なマージソートは、このためのもう1つの本当に良いものです。これは、入力を複数の異なるソート範囲の連結として扱い、マージアルゴリズムを使用してそれらを結合することによって機能するボトムアップマージソートバリアントです。すべての入力範囲が並べ替えられるまで、このプロセスを繰り返します。データがすでにソートされていて、O(n lg n)が最悪の場合、これはO(n)時間で実行されます。非常にエレガントですが、実際にはTimsortやsmoothsortのような他のいくつかの適応ソートほど良くありません。
他の誰もが言ったように、素朴なQuicksortには注意してください-ソートされたデータまたはほとんどソートされたデータでO(N ^ 2)のパフォーマンスが得られる可能性があります。それでも、ピボットの選択に適切なアルゴリズム(ランダムまたは3つの中央値- クイックソートのピボットの選択を参照)を使用すると、クイックソートは正常に機能します。
一般に、挿入ソートなどのアルゴリズムを選択することの難しさは、Quicksortが実際に高速になるほどデータの順序が適切でない場合を決定することです。
実際の答えを得るには、アルゴリズムをコーディングして、代表的なデータサンプルに対してそれらをプロファイリングする必要があると思うので、ここですべての答えを装うつもりはありません。しかし、私は一晩中この質問について考えていました。これが私にこれまでに起こったことであり、何がどこで最もうまく機能するかについての推測があります。
Nをアイテムの総数、Mを順序外の数とする。
バブルソートでは、2 * M + 1のようにN個のアイテムすべてを通過させる必要があります。Mが非常に小さい場合(0、1、2?)、これは非常に難しいでしょう。
Mが小さい(たとえば、log Nより小さい)場合、挿入ソートの平均パフォーマンスは非常に高くなります。ただし、私が見られないトリックがない限り、ワーストケースのパフォーマンスは非常に悪くなります。(正しいですか?注文の最後の項目が最初に来る場合、私が見る限り、すべての項目を挿入する必要があります。これにより、パフォーマンスが低下します。)このための信頼性の高い並べ替えアルゴリズムがあると思います。ケースですが、それが何かはわかりません。
Mが大きい(たとえば、log Nと等しいか大きい)場合、内省的ソートがほぼ確実に最適です。
これらすべての例外:実際に事前にソートされていない要素がわかっている場合は、それらのアイテムを引き出して、内省的ソートを使用してソートし、2つのソート済みリストを1つのソート済みリストにマージするのが最善の策です。故障しているアイテムがすぐにわかる場合は、これも良い一般的な解決策になります。しかし、これを行う簡単な方法を見つけることはできませんでした。
さらなる考察(一晩):M + 1 <N / Mの場合、リストをスキャンして、ソートされた行でN / Mのランを探し、そのランをいずれかの方向に展開して、アウトオブアウトを見つけることができます。 -注文商品。これは最大で2Nの比較になります。次に、並べ替えられていないアイテムを並べ替え、2つのリストで並べ替えられたマージを実行できます。全体の比較は、4N + M log2(M)のようなものより少なくなるはずです。これは、特殊化されていない並べ替えルーチンを打ち負かすものだと思います。(さらに考えました:これは私が考えていたよりもトリッキーですが、それでも合理的に可能だと思います。)
質問の別の解釈は、順序が狂っている項目の多くがあるかもしれないが、それらはリスト内のあるべき場所に非常に近いということです。(並べ替えられたリストから始めて、他のすべてのアイテムをその後ろに来るものと交換することを想像してください。)その場合、バブルソートは非常にうまく機能すると思います-パスの数はアイテムの最も遠い場所に比例すると思いますです。順不同のすべてのアイテムが挿入をトリガーするため、挿入ソートはうまく機能しません。内省的なソートなどもうまくいくと思います。
ソートアルゴリズム、データ構造、または上記へのリンクを持つ何かのための特定の実装が必要な場合、CodePlex の優れた「データ構造とアルゴリズム」プロジェクトをお勧めできますか?
ホイールを再発明することなく、必要なものがすべて揃っています。
私の小さな塩の粒だけ。
回答でこの目的のためのこのソートアルゴリズムの素晴らしいコレクションは、Gnome Sortを欠いているように見えます。これも適切であり、おそらく実装の労力が最小です。
まあそれはユースケースに依存します。変更される要素がわかっている場合は、削除および挿入が私にとっては最良のケースです。
QuickSortに近づかないでください。事前にソートされたデータに対しては非常に非効率的です。挿入ソートは、できるだけ少数の値を移動することにより、ほとんどソートされたデータを適切に処理します。