web-dev-qa-db-ja.com

各ソートアルゴリズムはいつ使用されますか?

特定の並べ替えアルゴリズムが他の並べ替えアルゴリズムよりも優先される場合の使用例-merge sort vs quick sort vs heap sort vs intro sortなど

サイズ、データ構造のタイプ、利用可能なメモリとキャッシュ、およびCPUパフォーマンスに基づいてそれらを使用する際の推奨ガイドはありますか?

152
sam

まず、定義は非常に重要です。A安定した並べ替えは、同一のキーを持つ要素を並べ替えないことが保証されている定義です。

推奨事項:

クイックソート:安定したソートが不要で、平均的なケースパフォーマンスが最悪のケースパフォーマンスよりも重要な場合。クイックソートは平均でO(N log N)、最悪の場合はO(N ^ 2)です。適切な実装では、O(log N)補助ストレージを再帰用のスタックスペースの形式で使用します。

Merge sort:安定したO(N log N)ソートが必要な場合、これが唯一のオプションです。唯一の欠点は、O(N)補助スペースを使用し、クイックソートよりもわずかに大きい定数があることです。いくつかのインプレースマージソートがありますが、知る限りでは、それらはすべて安定していないか、O(N log N)より悪いです。 O(N log N)のインプレースソートでさえ、古いマージソートよりも定数が非常に大きいため、有用なアルゴリズムよりも理論上の好奇心が強いです。

ヒープソート:安定したソートを必要とせず、平均的なケースパフォーマンスよりも最悪のケースパフォーマンスを重視する場合。 O(N log N)であることが保証されており、O(1)補助スペースを使用します。これは、非常に大きな入力でヒープまたはスタックスペースが突然不足することを意味します。

Introsort:これは、特定の再帰深度の後にヒープソートに切り替えて、クイックソートのO(N ^ 2)ワーストケースを回避するクイックソートです。 O(N log N)のパフォーマンスが保証されているクイックソートの平均的なケースが得られるため、通常のクイックソートよりも常に優れています。おそらく、これの代わりにヒープソートを使用する唯一の理由は、O(log N)スタックスペースが実質的に重要である、メモリが厳しく制限されたシステムにあることです。

挿入ソート:クイックソートまたはマージソートの基本ケースを含め、Nが小さいことが保証されている場合。これはO(N ^ 2)ですが、定数は非常に小さく、安定したソートです。

Bubble sort、selection sort:何か早くて汚いことをしているとき、何らかの理由で標準ライブラリのソートアルゴリズムを使用することはできません。これらが挿入ソートより優れている唯一の利点は、実装が少し簡単であることです。


非比較ソート:かなり限られた条件下では、O(N log N)バリアを破ってO(N)でソートすることができます。試してみる価値があるいくつかのケースを次に示します。

カウントの並べ替え:範囲が制限されている整数を並べ替える場合。

基数ソート: log(N)がKよりも大幅に大きい場合(Kは基数の桁数)。

Bucket sort:入力がほぼ均一に分散されることを保証できる場合。

287
dsimcha

さまざまな種類のデータとアルゴリズムのアニメーションのセットは、 sorting-algorithms.com にあります。

43
Chip Uni

Quicksortは、通常、平均で最速ですが、最悪の最悪の動作がいくつかあります。したがって、不正なデータによってO(N^2)が提供されないことを保証する必要がある場合は、回避する必要があります。

Merge-sortは余分なメモリを使用しますが、外部ソート(つまり、メモリに収まらない巨大なファイル)に特に適しています。

ヒープソートはインプレースでソートでき、最悪の場合の2次動作はありませんが、ほとんどの場合、平均してクイックソートよりも低速です。

制限された範囲の整数のみが関係する場合、何らかの基数ソートを使用して非常に高速にすることができます。

99%のケースでは、通常はクイックソートに基づいているライブラリーソートで問題ありません。

25
Eli Bendersky

ソートアルゴリズムに関するWikipediaページには、優れた比較チャートがあります。

http://en.wikipedia.org/wiki/Sorting_algorithm#Comparison_of_algorithms

4
Dan Lorenc

比較/アニメーションへの提供されたリンクが考慮しないのは、データの量が利用可能なメモリを超えたときです。この時点で、データを通過する回数、つまりI/Oコストがランタイムを支配します。それが必要な場合は、通常、マージソートとヒープソートのバリエーションをカバーする「外部ソート」を読んでください。

http://corte.si/posts/code/visualisingsorting/index.html および http://corte.si/posts/code/timsort/index.html もさまざまな並べ替えアルゴリズムを比較するクールな画像があります。

3
Alex Brasetvik

@ dsimchaが書いた:カウントの並べ替え:制限された範囲の整数を並べ替えるとき

それを次のように変更します。

ソートのカウント:正の整数(ピジョンホールによる0-Integer.MAX_VALUE-2)をソートする場合。

線形時間でも効率ヒューリスティックとして常に最大値と最小値を取得できます。
また、中間アレイ用に少なくともn個の追加スペースが必要であり、明らかに安定しています。

/**
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

(実際にMAX_VALUE-2を許可しますが)を参照してください。 Java配列には最大サイズがありますか?

また、基数ソートの複雑さは、Wordサイズwの整数であるn個のキーに対してO(wn)であることを説明します。 wが定数として表されることもありますが、これは基数ソートを(十分に大きいnの場合)最適な比較ベースのソートアルゴリズムよりも優れたものにします。ただし、一般的にwは定数と見なすことはできません。n個のキーがすべて異なる場合、ランダムアクセスマシンがそれらをメモリに格納できるようにするには、少なくともlog nである必要があります。 (n log n)。 (ウィキペディアから)

0
Droid Teahouse