web-dev-qa-db-ja.com

ほとんどのソートされたデータに最も適したソートアルゴリズムはどれですか?

ほとんどのソートされたデータに最も適したソートアルゴリズムはどれですか?

166
graphics

非常に科学的な監視方法に基づいています アニメーションGIF 挿入とバブルの並べ替えが良い候補だと思います。

251
Tom Ritter

少数のアイテムのみ=>挿入ソート

ほとんどの項目はすでにソート済みです=> INSERTION SORT

最悪のシナリオに関する懸念=> HEAP SORT

良い平均ケースの結果に興味がある=> QUICKSORT

アイテムは密集した宇宙から描かれています=> BUCKET SORT

できるだけ少ないコードを書きたい== INSERTION SORT

103
Jiaji Li

ティムソート

Timsort は、「適応性のある安定した自然なマージソート」であり、「多くの種類の半順序配列の超自然的なパフォーマンス(未満lg(N!)の比較が必要で、N-1)ほどです」。 Pythonの組み込みsort()はしばらくの間このアルゴリズムを使用しており、明らかに良い結果が得られています。これは、実際のデータセットでよく発生する、入力内の部分的にソートされたサブシーケンスを検出して活用するように特別に設計されています。現実世界では、リスト内のアイテムをスワップするよりも比較がはるかに高価であることがよくあります。これは、通常、ポインターをスワップするだけであり、多くの場合、Timsortが優れた選択肢になります。ただし、比較が常に非常に安価であることがわかっている場合(たとえば、32ビット整数を並べ替えるおもちゃのプログラムを作成する場合)、パフォーマンスが向上する可能性のある他のアルゴリズムが存在します。 timsortを利用する最も簡単な方法はもちろんPythonを使用することですが、Pythonはオープンソースであるため、コードを借用することもできます。また、上記の説明には、独自の実装を記述するのに十分な詳細が含まれています。

30
zaphod

次の動作を持つ挿入ソート:

  1. スロット1..nの各要素kについて、最初にel[k] >= el[k-1]かどうかを確認します。その場合、次の要素に進みます。 (明らかに最初の要素をスキップします。)
  2. そうでない場合は、要素1..k-1でバイナリ検索を使用して挿入位置を決定し、要素をスクートします。 (これは、k>Tで、Tが何らかのしきい値である場合にのみ実行できます。小さいkでこれは過剰です。)

このメソッドは、比較の数が最も少なくなります。

19
Jason Cohen

内省的な並べ替えを試してください。 http://en.wikipedia.org/wiki/Introsort

これはクイックソートに基づいていますが、クイックソートがほぼソートされたリストに対して持つ最悪の動作を回避します。

トリックは、このソートアルゴリズムが、クイックソートがワーストケースモードになり、ヒープソートまたはマージソートに切り替わるケースを検出することです。ほぼソートされていないパーティションは、単純でないパーティション方式によって検出され、小さなパーティションは挿入ソートを使用して処理されます。

コードと複雑さを犠牲にして、すべての主要な並べ替えアルゴリズムを利用できます。そして、データがどのように見えても、最悪の場合の動作に陥ることはありません。

C++プログラマなら、std :: sortアルゴリズムを確認してください。内部で内省的なソートをすでに使用している場合があります。

11

Splaysort は、適応型バイナリツリーの一種である splay trees に基づくあいまいなソート方法です。 Splaysortは、部分的にソートされたデータだけでなく、部分的に逆ソートされたデータ、または実際にあらゆる種類の既存の順序を持​​つデータにも適しています。一般的な場合はO(nlogn)であり、データが何らかの方法(フォワード、リバース、オルガンパイプなど)でソートされている場合はO(n)です。 )。

挿入ソートよりも優れている点は、データがまったくソートされていない場合にO(n ^ 2)の動作に戻らないことです。したがって、データを使用する前に部分的にソートされていることを完全に確認する必要はありません。

欠点は、必要なスプレーツリー構造の余分なスペースオーバーヘッドと、スプレーツリーの構築と破棄に必要な時間です。ただし、予想されるデータのサイズと事前ソートの量によっては、速度を向上させるためにオーバーヘッドが必要になる場合があります。

splaysortの論文 Software--Practice&Experienceで公開されました。

7
TimB

挿入またはシェルソート!

5
ninesided

Dijkstraのsmoothsortは、すでにソートされたデータに最適です。これは、O(n lg n)ワーストケースおよびO(n)ベストケースで実行されるヒープソートバリアントです。 I 分析を書きました アルゴリズムの仕組みです。どのように機能するのか知りたい場合に備えて。

Naturalマージソートは、これに適したもう1つの優れたものです。これは、入力を複数の異なるソート範囲の連結として扱い、マージアルゴリズムを使用してそれらを結合することにより機能するボトムアップマージソートバリアントです。すべての入力範囲がソートされるまで、このプロセスを繰り返します。データが既にソートされており、O(n lg n)最悪の場合、これはO(n)時間で実行されます。それは非常にエレガントですが、実際にはティムソートやスムースソートのような他の適応ソートほど優れていません。

5
templatetypedef

要素が既にソートされているか、要素が少ない場合は、挿入ソートの完璧なユースケースになります!

4
Roger

挿入ソートには時間がかかりますO(n +反転の数)。

反転は、(i, j)のようなi < j && a[i] > a[j]のペアです。つまり、順不同のペアです。

「ほぼソートされている」ことの1つの尺度は、反転の数です。つまり、「ほぼソートされたデータ」を使用して、反転の少ないデータを意味することができます。反転の数が線形であることがわかっている場合(たとえば、O(1))要素を並べ替えたリストに追加したばかりの場合)、挿入並べ替えにはO(n)時間かかります。

3
Jonas Kölker

ここですべての答えを持っているふりをするつもりはありません。実際の答えを得るには、アルゴリズムをコーディングし、代表的なデータサンプルに対してプロファイリングする必要があると思うからです。しかし、私は一晩中この質問について考えてきました。これまでに私に起こったことと、何がどこで最もうまくいくかについての推測です。

Nを合計アイテム数、Mを異常な数とします。

バブルソートでは、N個すべてのアイテムを2 * M + 1パスするようなものを作成する必要があります。 Mが非常に小さい(0、1、2?)場合、これは非常に難しいと思います。

Mが小さい(たとえば、log Nより小さい)場合、挿入ソートの平均パフォーマンスは優れています。ただし、私が見ていないトリックがない限り、最悪の場合のパフォーマンスは非常に悪くなります。 (そうですか?順序の最後のアイテムが最初に来る場合、私が見る限り、すべてのアイテムを挿入する必要があります。これによりパフォーマンスが低下します。)これには、より信頼性の高いソートアルゴリズムがあると思いますしかし、私はそれが何であるか分かりません。

Mがより大きい(たとえば、log Nと等しいか大きい)場合、内省的なソートがほぼ確実に最適です。

すべての例外:並べ替えられていない要素が実際に事前にわかっている場合は、それらのアイテムを引き出し、内省的な並べ替えを使用して並べ替え、2つの並べ替えられたリストを1つの並べ替えられたリストにマージするのが最善の策です。どのアイテムが故障しているかをすぐに把握できれば、これも良い一般的な解決策になりますが、これを行う簡単な方法はわかりませんでした。

さらなる考え(一晩):M + 1 <N/Mの場合、リストをスキャンして、ソートされた行のN/Mの実行を探し、次にその実行をいずれかの方向に展開して、範囲外を見つけることができます-注文アイテム。それには最大2Nの比較が必要です。その後、未ソートのアイテムをソートし、2つのリストでソート済みマージを実行できます。合計の比較は、4N + M log2(M)のようなものよりも少ないはずです。これは、特殊化されていない並べ替えルーチンに勝るものです。 (さらに考えた:これは私が考えていたよりも難しいが、それでも合理的に可能だと思う。)

質問の別の解釈は、多くの異常なアイテムがあるかもしれないが、それらはリストのどこにあるべきかに非常に近いということです。 (ソートされたリストから始めて、他のすべてのアイテムを後続のリストと交換することを想像してください。)その場合、バブルソートは非常にうまく機能すると思います-パスの数は、アイテムの最も外側の場所に比例すると思いますです。順不同のアイテムはすべて挿入をトリガーするため、挿入ソートはうまく機能しません。内省的なソートなどもうまくいくと思います。

2
Sol

他の皆が言ったように、素朴なクイックソートに注意してください-ソートされたデータまたはほぼソートされたデータでO(N ^ 2)のパフォーマンスを持つことができます。それでも、ピボットの選択に適したアルゴリズム(ランダムまたは3の中央値- クイックソートのピボットの選択 を参照)を使用すると、クイックソートは正常に機能します。

一般的に、挿入ソートなどのアルゴリズムを選択することの難しさは、Quicksortが本当に速くなるほどデータが十分に乱れている場合を判断することです。

2

答えのこの目的のためのソートアルゴリズムのこのニースのコレクションは、 Gnome Sort を欠いているようで、これも適切であり、おそらく最小限の実装作業を必要とします。

1
haraldkl

ソートアルゴリズム、データ構造、または上記へのリンクを持つものの特定の実装が必要な場合は、CodePlexの優れた "データ構造とアルゴリズム" プロジェクトをお勧めしますか?

車輪を再発明することなく、必要なものはすべて揃っています。

ほんの少しの塩です。

1
Maxime Rouiller

バブルソートが間違いなく勝者ですレーダーの次の1つは挿入ソートです。

0
vCillusion

バブルソート(または、より安全でありながら双方向のバブルソート)は、ほとんどソートされたリストに理想的です。完全にソートされたt。コームソートはバブルソートになります。

0
Brian

まあそれはユースケースに依存します。どの要素が変更されているかがわかっている場合、削除と挿入は、私に関する限り最良のケースです。

0
Helin Wang

挿入ソートは、ソートされた入力に対するO(n)ベストケースです。また、ほとんどのソートされた入力に非常に近い(クイックソートよりも優れています)。

0
jjnguy

ponderヒープを試す。 O(n lg n)ソートの中で最も一貫していると思います。

0
Paul Nathan