web-dev-qa-db-ja.com

なぜ基数ソートよりクイックソートの方が人気があるのですか?

なぜクイックソート(またはイントロソート)、または比較ベースのソートアルゴリズムが基数ソートよりも一般的ですか?特に数値のソートに。

基数ソートは比較ベースではないため、O(n logn)よりも高速である可能性があります。実際には、O(k n)であり、kは各アイテムを表すために使用されるビット数です。また、使用するバケットの数を選択でき、必要なメモリがマージソートの要件より少ない場合があるため、メモリのオーバーヘッドは重要ではありません。

それはキャッシングと関係がありますか?または、配列内の整数のランダムなバイトにアクセスしますか?

41
Daniyar

2つの議論が思い浮かびます。

  1. Quicksort/Introsortはより柔軟です:

    クイックソートとイントロソートは、あらゆる種類のデータでうまく機能します。並べ替えに必要なのは、アイテムを比較する可能性だけです。これは数値で簡単ですが、他のデータも並べ替えることができます。

    一方、基数ソートは、バイナリ表現でソートするだけです。アイテムを相互に比較することはありません。

  2. 基数ソートにはより多くのメモリが必要です。

    私が見てきたすべての基数ソート実装は、部分的なソート結果を格納するために2次バッファーを使用します。これにより、ソートアルゴリズムのメモリ要件が増加します。数キロバイトしかソートしない場合は問題にならないかもしれませんが、ギガバイトの範囲に入ると、大きな違いが生じます。

    私が正しいことを覚えていれば、基数ソートアルゴリズムが紙に存在します。

24

明確な答えの1つは、基数でのみ数値に制限される一方で、クイックソート(つまり、比較可能なもの)を使用して任意のタイプをソートできることです。また、IMOクイックソートの方がはるかに直感的です。

11

(ほとんどの)実世界のユースケースでは、基数ソートは遅くなります。

1つの理由は、アルゴリズムの複雑さです。

アイテムが一意の場合、k> = log(n)。アイテムが重複していても、k <log(n)が小さい問題のセットは小さくなります。

もう1つは実装です。

追加のメモリ要件(それ自体は不利です)は、キャッシュのパフォーマンスに悪影響を及ぼします。

標準ライブラリのような多くのライブラリはQuicksortを使用していると言っても安全です。ほとんどの場合、Quicksortの方がパフォーマンスが優れているからです。 「実装が難しい」「直感的でない」が大きな要因だとは思いません。

8
Plow

Wikipedia で述べたように

他のソートアルゴリズムと比較した基数ソートの効率性のトピックは、ややトリッキーであり、かなり多くの誤解の対象となっています。基数の並べ替えが、最適な比較ベースのアルゴリズムと同等に効率的であるか、効率的でないか、または効率的であるかは、行われた仮定の詳細に依存します。基数ソート効率は、桁数がd以下のn個のキーの場合、O(d・n)です。時々dは定数として表され、基数ソートが(十分に大きなnに対して)最適な比較ベースのソートアルゴリズム(すべてO(n・log(n))の必要な比較よりも良い)になります。ただし、一般にdは定数と見なすことはできません。 特に、すべてのキーが異なるという一般的な(ただし暗黙的な場合もある)仮定の下では、dは少なくともlog(n)の次数でなければなりません。キー)時間の複雑さO(n・log(n))。これにより、基数ソートは、比較ベースの最良のソートと同じくらい効率的になります(キーがlog(n)よりはるかに長い場合はさらに悪くなります)。

反対の議論は、比較ベースのアルゴリズムは、実際の時間の複雑さではなく、比較の数で測定されます。一部の仮定では、比較は平均して一定の時間になりますが、他の仮定ではそうではありません。ランダムに生成されたキーの比較は、平均で一定の時間がかかります。キーは、最初のビットが半分の場合で異なり、2番目のビットが残りの半分の半分で異なるなどです。その結果、平均2ビットになります。比較する必要があります。並べ替えアルゴリズムでは、最初に行われた比較はランダム性の条件を満たしますが、並べ替えが進むにつれて、比較されるキーは明らかにランダムに選択されなくなります。たとえば、ボトムアップマージソートについて考えてみます。最初のパスはランダムなキーのペアを比較しますが、最後のパスはソート順が非常に近いキーを比較します。

決定的な要素は、キーの配布方法です。基数ソートの最良のケースは、それらが連続したビットパターンと見なされることです。これにより、キーが可能な限り短くなりますが、キーが異なると想定されます。これにより、基数ソートはO(n・log(n))になりますが、比較に基づくソートは、この仮定のもとでは比較が一定時間にならないため、効率的ではありません。代わりに、キーが定数k> 1および2を底とする対数の長さk・log(n)のビットパターンであり、それらが一様にランダムであると仮定した場合、基数ソートはO(n・log(n)のままです。 )ですが、比較ベースのソートも同様です。「追加の」長さにより、ソートされた結果で連続するキーでさえ、比較が平均して一定の時間になるように十分に異なるためです。 キーがO(log(n))よりも長いがランダムである場合、基数ソートは劣ります。他にも多くの仮定があります。同様に、大部分は正確な比較を行うために注意深い研究を必要とします。

4
Abhinav Chauhan

他の回答で行われたポイントは有効ですが、いくつかのコメントで言及されているあなたの懸念に関する限り

...数値のデフォルトの並べ替えアルゴリズムがクイックソートを使用して実装されているという事実。特にライブラリの実装...

クイックソートは「安全な」選択です。カウントソートに基づく基数ソートの潜在的な実行時間は非常に魅力的です。ただし、基数ソートは、悪意のある/不幸なデータセットでのパフォーマンス低下の影響を受けやすくなっています。ソートされるキーの桁数がソートされるキーの数に近づくと、基数ソートは無視できないスペースの複雑さとともにn ^ 2で実行され、数値以外の組み込みランタイム定数がかなり高くなる傾向がありますソートされるキーの桁数。
マージソートは、その振る舞いが、ある意味で、各機会(中央値)で最適なピボットを選択するクイックソートに類似しているため、魅力的です。ただし、かなりのスペースの複雑さが伴います。基数ほど悪意のある/不幸なデータの影響を受けにくいだけでなく、魅力的な実行可能時間も提供しません。基本的なクイックソートは、ほとんど(または完全に)ソートされたデータセットを除いて、ほとんどのデータセットで非常にうまく機能し、スペースが非常に複雑になります。
クイックソートの脆弱性は、ランダム化されたクイックソートに変換することで簡単に対処できます。基数ソートの脆弱性は、ライブラリのユーザーを本質的に制限するソートされるキーに制限を設けることによって解決されます。クイックソートは、小さいデータセットでのマージよりもパフォーマンスが高く、マージがより高速である場合に適度に実行されます。
ライブラリを実装するとき、それを一般的に有用にする必要があります。これらの例、Webアプリケーション、および非常に制限されたマイクロコントローラーを備えた小型デバイスを見てみましょう。 Webアプリケーションは定期的に悪意のあるデータを処理する必要があり、さまざまなニーズもあります。事前に条件付けされた制限のあるライブラリは、あまり役に立ちません。マイクロコントローラの場合、スペースに制限があり、保存できるわずかなビットを放棄できない場合があります。クイックソートはスペースを節約し、遅いという状況が発生した場合に一定の乗数で遅く完了するだけです。
まとめると-
1。)ライブラリは、可能な限り多くの一般的なユーザビリティのためにコード化されることが多い
2。)特に、多くの場合、最高のパフォーマンスである場合は、良好なパフォーマンスが許容されます。
3。)スペースは常に主要な問題であるとは限りませんが、そうである場合、明示的に制限されていることがよくあります。

1
Culex