web-dev-qa-db-ja.com

クイックソートはマージソートよりも優れているのはなぜですか?

私は面接中にこの質問を受けました。両方ともO(nlogn)ですが、ほとんどの人はMergesortの代わりにQuicksortを使用します。何故ですか?

クイックソートはO(n2)最悪の場合の実行時間とO(nログn)平均ケース実行時間ただし、多くのシナリオでマージソートが優れているのは、多くの要因がアルゴリズムの実行時間に影響を与えるためです。これらすべてをまとめると、クイックソートが無効になります。

特に、頻繁に引用されるソートアルゴリズムのランタイムは、データのソートに必要な比較数またはスワップ数を表します。特にこれは、基盤となるハードウェア設計とは無関係であるため、これは確かにパフォーマンスの優れた尺度です。しかし、参照の局所性などの他のこと(つまり、おそらくキャッシュ内にある要素をたくさん読むのでしょうか)も、現在のハードウェアで重要な役割を果たします。特にクイックソートでは、追加のスペースがほとんど必要なく、キャッシュの局所性が優れているため、多くの場合、マージソートよりも速くなります。

さらに、クイックソートの最悪の場合のOの実行時間を避けるのは非常に簡単です。n2)ピボットの適切な選択を使用することによって、ほぼ完全に - ランダムに選択するなど(これは優れた戦略です)。

実際には、最近のクイックソートの実装(特にlibstdc ++のstd::sort)は実際には introsort で、理論上の最悪の場合はO(nログn)マージソートと同じです。再帰の深さを制限し、logを超えたら別のアルゴリズム( heapsort )に切り替えることでこれを実現します。n

253
Konrad Rudolph

多くの人が指摘しているように、クイックソートの平均ケースパフォーマンスはマージソートより速いです。 しかしこれは、オンデマンドでメモリにアクセスする時間が一定であると仮定している場合にのみ当てはまります。

RAMでは、この仮定は一般的にはそれほど悪くはありません(キャッシュのために常に正しいとは限りませんが、それほど悪くはありません)。ただし、データ構造がディスク上に存在するのに十分な大きさの場合、quicksortは平均的なディスクが毎秒200のランダムシークを実行するという事実によって殺されます。 。しかし、同じディスクで、毎秒1メガバイトのデータを順番に読み書きするのに問題はありません。これがまさにマージソートの動作です。

したがって、データをディスク上でソートする必要がある場合は、実際にはマージソートでバリエーションを使用することをお勧めします。 (通常はサブリストをクイックソートしてから、サイズのしきい値を超えてマージします。)

さらに、そのサイズのデータ​​セットを使って何かをしなければならない場合は、ディスクへのシークを避ける方法について十分に検討してください。たとえば、データベースに大量のデータをロードする前にインデックスを削除し、後でインデックスを再構築することが標準的なアドバイスです。ロード中にインデックスを維持することは、常にディスクをシークすることを意味します。対照的に、インデックスを削除すると、データベースはまず対処する情報をソートし(もちろんマージソートを使用して)、次にインデックスのBTREEデータ構造にロードすることでインデックスを再構築できます。 (BTREEは自然に順番に保たれているので、ディスクへのシークが少ないソート済みデータセットからロードすることができます。)

ディスクシークを回避する方法を理解することで、データ処理ジョブに数日または数週間ではなく数時間かかるようにする機会が何度もありました。

271
user11318

実際には、QuickSortはO(n2)その平均ケース実行時間はO(nlog(n))ですが、最悪ケースはO(n)です2これは、ユニークな項目がほとんど含まれていないリストで実行したときに発生します。ランダム化はO(n)を取ります。もちろん、これによって最悪のケースが変わることはありません。悪意のあるユーザーがソートに長時間を要するのを防ぐだけです。

QuickSortは以下の理由でより人気があります。

  1. インプレースです(MergeSortはソートされる要素の数に比例した追加のメモリを必要とします)。
  2. 小さな隠し定数があります。
87
Dark Shikari

「それでも、ほとんどの人はMergesortの代わりにQuicksortを使用しています。それはなぜですか?」

与えられていない1つの心理的な理由は単にQuicksortがより巧妙に命名されているということです。すなわち良いマーケティング。

はい、トリプルパーティショニングを使ったQuicksortはおそらく最も良い汎用ソートアルゴリズムの1つですが、 "Quick"ソートが "Merge"ソートよりはるかに強力に聞こえるという事実を乗り越えることはできません。

29
Ash

他の人が指摘したように、クイックソートの最悪の場合はO(n ^ 2)で、マージソートとヒープソートはO(nlogn)のままです。しかし、平均して、3つすべてがO(nlogn)です。それで、それらは比較可能なケースの大多数のためです。

Quicksortを平均的に良くするのは、内側のループがいくつかの値を単一の値と比較することを意味しているのに対し、他の2つの場合は両方の項が比較ごとに異なるということです。つまり、Quicksortは他の2つのアルゴリズムの半分の読み取り数を実行します。最近のCPUでは、パフォーマンスはアクセス時間によって大きく左右されるため、結局、Quicksortは最初の大きな選択肢となります。

15
Javier

これまでに述べた3つのアルゴリズム(マージソート、クイックソート、ヒープソート)のうち、マージソートのみが安定しているものを付け加えたいと思います。つまり、同じキーを持つ値の順序は変わりません。場合によってはこれが望ましいです。

しかし実際には、ほとんどの人は平均的なパフォーマンスだけを必要とし、クイックソートは... quick =)

すべてのソートアルゴリズムには、長所と短所があります。概要については、 ソートアルゴリズムに関するWikipediaの記事 を参照してください。

8
Antti Rasinen

From Quicksortに関するウィキペディアのエントリ

Quicksortは、別の再帰的ソートアルゴリズムであるマージソートと競合しますが、最悪の場合のΘ(nlogn)実行時間という利点があります。 Mergesortはクイックソートやヒープソートとは異なり安定したソートであり、ディスクストレージやネットワーク接続ストレージなどのアクセスが遅いメディアに格納されたリンクリストや非常に大きなリストでの操作に簡単に適応できます。クイックソートはリンクされたリストを操作するように書くことができますが、ランダムアクセスなしではピボットの選択が悪いという欠点があります。マージソートの主なデメリットは、配列を操作する場合、最良の場合ではΘ(n)補助スペースが必要なのに対し、インプレース分割と末尾再帰を使用するクイックソートの変形ではΘ(logn)スペースしか使用しないことです。 (リンクリストを操作する場合、マージソートに必要なのは少量の一定量の補助記憶域だけです。)

7
gnobal

Mu! クイックソートは良くありません。マージソートとは異なる種類のアプリケーションに適しています。

Mergesortは、スピードが最も重要であり、最悪の場合のパフォーマンスが悪くなっても許容できず、余分なスペースがあるかどうかを検討する価値があります。 1

あなたは彼らが"彼らは両方O(nlogn) […]"だと言った。これは間違っています。 "Quicksortは最悪の場合、約n ^ 2/2の比較を使います。" 1

しかし、私の経験によると最も重要な特性は、命令型命令を使用してプログラミング言語を使用するときにソート中に使用できる順次アクセスの簡単な実装です。

1 Sedgewick、アルゴリズム

7
Roman Glass

Quicksortは実際には最速のソートアルゴリズムですが、O(n2)と同じぐらいひどく実行される可能性があるいくつかの病理学的ケースがあります。

ヒープソートはO(n * ln(n))で動作することが保証されており、有限の追加記憶域しか必要としません。しかし、実際のテストでは、ヒープソートの方がクイックソートよりも平均して著しく遅いことを示す多くの引用があります。

6
Niyaz

ウィキペディアの説明は:

通常、クイックソートは他のΘ(nlogn)アルゴリズムよりもはるかに高速です。これは、その内部ループがほとんどのアーキテクチャで効率的に実装できるためです。 。

クイックソート

Mergesort

クイックソートの実装にはないMergesortに必要な記憶容量(Ω(n))にも問題があると思います。最悪の場合、それらは同じ量のアルゴリズム時間ですが、マージソートはより多くのストレージを必要とします。

5
Mat Mannion

既存の優れた回答に、ベストケースから逸脱した場合のQuickSortの実行方法とその可能性に関するいくつかの数学を追加したいと思います。これは、O(n ^ 2)ケースが実際ではない理由を少しでもよく理解する助けになると思いますQuickSortのより洗練された実装に関する懸念。

ランダムアクセスの問題以外にも、QuickSortのパフォーマンスに影響を与える可能性のある2つの主な要因があり、どちらもピボットがソートされているデータと比較する方法に関連しています。

1)データ内の少数のキー。すべて同じ値のデータセットは、バニラ2パーティションQuickSortではn ^ 2時間でソートされます。これは、ピボット位置を除くすべての値が毎回片側に配置されるためです。最新の実装では、3パーティションソートの使用などの方法でこれに対処しています。これらのメソッドは、O(n)時間内にすべて同じ値のデータセットで実行されます。そのため、このような実装を使用すると、キーの数が少ない入力によって実際にパフォーマンス時間が改善され、心配する必要がなくなります。

2)ピボットの選択が極端に悪いと、最悪の場合のパフォーマンスを引き起こす可能性があります。理想的なケースでは、ピボットは常に、データが50%小さく、データが50%大きくなるようにして、各反復中に入力が半分に分割されるようにします。これにより、n回の比較が行われ、O(n * logn)時間のlog-2(n)回の再帰時間がスワップされます。

非理想的なピボット選択は実行時間にどのくらい影響しますか?

データの75%がピボットの片側にあるように、ピボットが一貫して選択される場合を考えてみましょう。まだO(n * logn)ですが、ログのベースが1/0.75または1.33に変更されました。ベースを変更するときのパフォーマンスの関係は、常にlog(2)/ log(newBase)で表される定数です。この場合、その定数は2.4です。したがって、このピボット選択の品質には、理想の2.4倍の時間がかかります。

これはどれほど速く悪化しますか?

ピボットの選択が(一貫して)非常に悪くなるまで、それほど高速ではありません。

  • 片側50%:(理想的な場合)
  • 片側75%:2.4倍の長さ
  • 片側90%:6.6倍の長さ
  • 片側95%:13.5倍の長さ
  • 片側99%:69倍の長さ

一方の側で100%に近づくと、実行のログ部分がnに近づき、実行全体が漸近的にO(n ^ 2)に近づきます。

QuickSortの単純な実装では、ソートされた配列(最初の要素のピボットの場合)または逆ソートされた配列(最後の要素のピボットの場合)などのケースは、最悪の場合のO(n ^ 2)実行時間を確実に生成します。さらに、予測可能なピボット選択を持つ実装は、最悪の場合の実行を生成するように設計されたデータによるDoS攻撃を受ける可能性があります。最新の実装では、ソート前のデータのランダム化、ランダムに選択された3つのインデックスの中央値の選択など、さまざまな方法でこれを回避しています。このランダム化では、2つのケースがあります。

  • 小さなデータセット。最悪の場合も合理的には可能ですが、O(n ^ 2)は壊滅的ではありません。nはn ^ 2も小さいほど十分に小さいからです。
  • 大規模なデータセット。最悪の場合は理論的には可能ですが、実際には不可能です。

パフォーマンスがどれほどひどくなるか?

可能性はvanishingly smallです。 5,000種類の値を考えてみましょう。

仮想的な実装では、ランダムに選択された3つのインデックスの中央値を使用してピボットを選択します。 25%-75%の範囲にあるピボットは「良好」であり、0%-25%または75%-100%の範囲にあるピボットは「不良」であると見なします。 3つのランダムインデックスの中央値を使用して確率分布を見ると、各再帰は11/16の確率で適切なピボットになります。数学を単純化するために、2つの保守的な(および誤った)仮定を行いましょう。

  1. 適切なピボットは常に25%/ 75%の分割で正確に行われ、2.4 *の理想的なケースで動作します。理想的なスプリットや25/75を超えるスプリットは得られません。

  2. 悪いピボットは常に最悪のケースであり、本質的にソリューションには何も貢献しません。

QuickSortの実装はn = 10で停止し、挿入ソートに切り替わります。そのため、5,000個の値の入力をここまで分割するには、22 25%/ 75%のピボットパーティションが必要です。 (10 * 1.333333 ^ 22> 5000)または、4990ワーストケースピボットが必要です。 任意のポイントで22個の良いピボットを蓄積すると、ソートが完了するため、最悪の場合またはそれに近い場合はextremely運が悪いことに注意してください。 n = 10にソートするために必要な22の良いピボットを実際に達成するのに88回の再帰が必要だった場合、4 * 2.4 *の理想的なケースまたは理想的なケースの実行時間の約10倍になります。 not 88回の再帰後、必要な22回の良好なピボットを達成する可能性はどのくらいですか?

二項確率分布 はそれに答えることができ、答えは約10 ^ -18です。 (nは88、kは21、pは0.6875)ユーザーは、[SORT]をクリックするのにかかる1秒間に、5,000項目のソートが実行されるのを見るよりも、約1,000倍雷に打たれる可能性が高い- より悪い 10 *理想的な場合より。この可能性は、データセットが大きくなるにつれて小さくなります。以下に、いくつかの配列サイズと、それに対応する10 *を超える実行の可能性を示します。

  • 640個のアイテムの配列:10 ^ -13(60回の試行のうち15回の適切なピボットポイントが必要)
  • 5,000個のアイテムの配列:10 ^ -18(88回の試行のうち22回の良好なピボットが必要)
  • 40,000個のアイテムの配列:10 ^ -23(116個のうち29個の適切なピボットが必要)

これは、現実よりも悪い2つの保守的な仮定に基づいていることに注意してください。したがって、実際のパフォーマンスはさらに向上し、残りの確率のバランスは理想よりも理想に近くなります。

最後に、他の人が述べたように、再帰スタックが深すぎる場合、ヒープソートに切り替えることにより、これらの不条理なケースは排除できます。したがって、TLDRは、QuickSortの適切な実装では、最悪のケース実際には存在しないであり、設計されており、実行がO(n * logn)時間で完了するためです。

4
Lance Wisely

クイックソートはマージソートよりも優れていません。 O(n ^ 2)(最悪の場合はめったに起こらない)では、クイックソートはマージソートのO(nlogn)よりはるかに遅くなる可能性があります。 QuickSortはオーバーヘッドが少ないため、小型で速度が遅いコンピュータでは、より優れています。しかし、今日のコンピュータは非常に高速であるため、マージソートの追加のオーバーヘッドはごくわずかであり、非常に遅いクイックソートのリスクは、ほとんどの場合、マージソートのわずかなオーバーヘッドをはるかに上回ります。

さらに、マージソートでは、同一のキーを持つアイテムを元の順序で残しておくという便利な属性があります。

4
xpda

マージソートとは異なり、クイックソートは補助スペースを使用しません。 Merge Sortは補助空間O(n)を使用します。しかし、Merge SortはO(nlogn)という最悪の場合の時間複雑度を持ちますが、Quick Sortの最悪の場合の複雑さはO(n ^ 2)で、配列がすでにソートされている場合に起こります。

3
Shantam Mittal

基本的な値のためにDualPivotQuickSortでもたらされた変更への答えはquicksort w.r.tに向かってわずかに傾くでしょう。これはJava 7でソートするために使われますJava.util.Arrays

It is proved that for the Dual-Pivot Quicksort the average number of
comparisons is 2*n*ln(n), the average number of swaps is 0.8*n*ln(n),
whereas classical Quicksort algorithm has 2*n*ln(n) and 1*n*ln(n)
respectively. Full mathematical proof see in attached proof.txt
and proof_add.txt files. Theoretical results are also confirmed
by experimental counting of the operations.

ここでJava7の実装を見つけることができます - http://grepcode.com/file/repository.grepcode.com/Java/root/jdk/openjdk/7-b147/Java/util/Arrays.Java

DualPivotQuickSortに関するさらにすばらしい読書 - http://permalink.gmane.org/gmane.comp.Java.openjdk.core-libs.devel/2628

3
SSR

マージソートでは、一般的なアルゴリズムは次のとおりです。

  1. 左側のサブ配列をソートする
  2. 正しいサブ配列をソートする
  3. 2つのソートされたサブ配列をマージする

最上位レベルでは、2つのソートされたサブ配列をマージすることはN個の要素を扱うことを含みます。

その1つ下のレベルでは、ステップ3を繰り返すたびにN/2個の要素を扱う必要がありますが、このプロセスを2回繰り返す必要があります。それで、あなたはまだ2 * N/2 == N要素を扱っています。

その1つ下のレベルでは、4 * N/4 == N要素をマージしています。再帰的スタックのすべての深さは、その深さに対するすべての呼び出しにわたって、同じ数の要素をマージすることを含みます。

代わりにクイックソートアルゴリズムを検討してください。

  1. ピボットポイントを選ぶ
  2. ピボットポイントを配列内の正しい場所に配置します。小さい要素はすべて左側に配置し、大きい要素は右側に配置します。
  3. 左部分配列をソートする
  4. 右部分配列をソートする

最上位レベルでは、サイズNの配列を扱っています。次に、1つのピボットポイントを選択し、それを正しい位置に配置してから、残りのアルゴリズムでは完全に無視できます。

その1つ下のレベルでは、結合サイズがN-1の2つのサブ配列を処理しています(つまり、前のピボットポイントを引いたものです)。サブアレイごとにピボットポイントを選択します。これは最大2つの追加のピボットポイントになります。

その1つ下のレベルでは、上記と同じ理由で、組み合わせサイズN-3の4つのサブアレイを扱っています。

それからN-7 ...それからN-15 ...それからN-32 ...

再帰スタックの深さはほぼ同じ(logN)のままです。 merge-sortでは、再帰スタックの各レベルで、常にN要素のマージを扱っています。ただし、クイックソートを使用すると、処理する要素の数はスタックを下るにつれて減少します。例えば、再帰的スタックの途中で深さを見ると、扱っている要素の数はN - 2 ^((logN)/ 2))== N - sqrt(N)です。

免責事項:マージソートでは、毎回2つのまったく等しいチャンクに配列を分割するため、再帰的な深さは厳密にlogNになります。クイックソートでは、ピボットポイントが正確に配列の中央にくることはほとんどないため、再帰スタックの深さはlogNよりわずかに大きくなる可能性があります。この要素と上記の要素が実際にアルゴリズムの複雑さにどの程度大きな役割を果たすかを見るために、私は数学をしていません。

3
RvPr

クイックソートは、平均的なケースの複雑さが優れていますが、アプリケーションによっては間違った選択です。クイックソートは、サービス拒否攻撃に対して脆弱です。攻撃者がソートする入力を選択できる場合、攻撃者は最悪の場合に時間の複雑さo(n ^ 2)をとる集合を簡単に構築できます。

Mergesortの平均的なケースの複雑さと最悪のケースの複雑さは同じであり、同じ問題を抱えることはありません。マージソートのこの特性は、リアルタイムシステムにとっても優れた選択となります。これは、実行速度が大幅に遅くなる原因となる病理学的ケースがないためです。

これらの理由から、私はQuickSortよりもMergesortの大ファンです。

2
Simon Johnson

両方とも同じ複雑さクラスに属していますが、それは両方が同じランタイムを持っているという意味ではありません。クイックソートは通常、マージソートよりも高速です。これは、厳密な実装をコーディングする方が簡単であり、操作を高速化できるためです。そのクイックソートは一般的に人々がマージソートの代わりに使うより速いからです。

しかしながら!私は個人的には、マージソートまたはクイックソートのパフォーマンスが悪い場合にはマージソートに低下するクイックソートの変種を使用することがよくあります。覚えておいてください。クイックソートは平均でO(n log n)のみです。最悪の場合はO(n ^ 2)です。マージソートは常にO(n log n)です。リアルタイムのパフォーマンスや応答性が必須であり、入力データが悪意のあるソースからのものである可能性がある場合は、単純なクイックソートを使用しないでください。

2
DJ Capelis

クイックソートは最悪の場合O(n ^ 2)ですが、平均的な場合は一貫してマージソートを実行します。各アルゴリズムはO(nlogn)ですが、Big Oについて話をするときには、複雑度の低い要素は除外しています。クイックソートは、一定の要因に関してはマージソートよりも大幅に改善されています。

併合ソートにはO(2n)メモリも必要ですが、クイックソートはその場で行うことができます(O(n)のみが必要です)。これは、マージソートよりもクイックソートの方が一般的に好まれるもう1つの理由です。

追加情報:

クイックソートの最悪の場合は、ピボットの選択が不適切な場合に発生します。次の例を見てください。

[5、4、3、2、1]

ピボットがグループ内の最小または最大数として選択されている場合、クイックソートはO(n ^ 2)で実行されます。リストの最大または最小の25%に含まれる要素を選択する確率は0.5です。それはアルゴリズムに良いピボットである可能性を0.5に与えます。私たちが典型的なピボット選択アルゴリズム(例えば、ランダムな要素を選ぶ)を採用するならば、ピボットのあらゆる選択に対して良いピボットを選ぶ可能性は0.5です。大きなサイズのコレクションの場合、常に貧弱なピボットを選択する確率は0.5 * nです。この確率に基づいて、クイックソートは平均的な(そして典型的な)ケースに対して効率的です。

2
Wade Anderson

クイックソートが良いのはなぜですか?

  • QuickSortは、最悪の場合にN ^ 2、平均の場合にNlogNを取ります。最悪の場合は、データがソートされたときに発生します。ソートが開始される前に、これはランダムシャッフルによって軽減されることができます。
  • QuickSortは、マージソートによって消費される余分なメモリを消費しません。
  • データセットが大きく、同一の項目がある場合は、3分割を使用することでQuicksortの複雑さが軽減されます。同一項目の数が多いほど、ソートは良くなります。すべての項目が同一の場合は、線形時間でソートされます。 [これはほとんどのライブラリのデフォルトの実装です]

クイックソートは常にマージソートより優れていますか?

実際は違います

  • マージソートは安定していますが、クイックソートは安定していません。そのため、出力の安定性が必要な場合は、Mergesortを使用します。安定性は多くの実用的な用途において必要とされる。
  • メモリは最近安いです。したがって、Mergesortによって使用される追加のメモリがアプリケーションにとって重要ではない場合でも、Mergesortを使用しても問題はありません。

注:Javaでは、Arrays.sort()関数はプリミティブデータ型にはQuicksortを、オブジェクトデータ型にはMergesortを使用します。オブジェクトはメモリのオーバーヘッドを消費するため、Mergesortのオーバーヘッドを少し追加してもパフォーマンスの観点からは問題にならない可能性があります。

参考文献第3週、CourseraのプリンストンアルゴリズムコースのQuickSortビデオをご覧ください

2

これはかなり古い質問ですが、最近両方を扱ったので、ここに2cがあります。

ソートのニーズを平均してマージン〜N log Nで比較します。すでに(ほぼ)ソートされたソート済み配列の場合、マージ中に常に「左」の部分を1/2 N回選択し、次に右側の1/2 N要素をコピーするので、これは1/2 N log Nになります。さらに、すでにソートされた入力がプロセッサの分岐予測子を輝かせますが、ほとんどすべての分岐を正しく推測するため、パイプラインの機能停止を防ぐことができます。

平均的なクイックソートには、約1.38 N log Nの比較が必要です。比較の観点からは既にソートされている配列から大きな利益は得られません(ただし、スワップの観点から、そしておそらくCPU内部の分岐予測の観点からはそうです)。

かなり近代的なプロセッサの私のベンチマークは以下を示しています:

比較関数がコールバック関数の場合(qsort()libcの実装のように)、クイックソートはランダム入力でマージソートより15%遅く、64ビット整数のソート済み配列で30%遅くなります。

一方、比較がコールバックではない場合、私の経験ではクイックソートはマージソートより最大25%パフォーマンスが優れています。

しかし、あなたの(大きな)配列が非常に少数のユニークな値を持っているなら、マージソートはいずれにせよクイックソートに勝ち始めます。

つまり、比較が高価な場合(例:コールバック関数、文字列の比較、構造体の多くの部分の比較、主に2〜3番目に違いがある場合) - その可能性は高いでしょう。マージソート付き。単純なタスクの場合はクイックソートが速くなります。

- QuicksortはN ^ 2になる可能性があるが、Sedgewickは、ランダム化された優れた実装では、N ^ 2よりも雷に打たれてソートを実行する可能性が高いと主張している - Mergesortは追加のスペースを必要とする

2
virco

再帰呼び出しの数を数えることによって、両方のソートアルゴリズムを試したとき、quicksortは一貫して併合よりも再帰呼び出しが少なくなります。クイックソートにはピボットがあり、ピボットは次の再帰呼び出しに含まれないためです。こうすることで、クイックソートはマージソートよりも速く再帰的な基本ケースに到達することができます。

2

クイックソートとマージソートのちょっとした追加。

ソート項目の種類によっても異なります。項目へのアクセス、スワップ、および比較がプレーンメモリ内の整数の比較のような単純な操作ではない場合、マージソートが望ましいアルゴリズムになることがあります。

たとえば、リモートサーバー上のネットワークプロトコルを使用してアイテムを並べ替えます。

また、 "リンクリスト"のようなカスタムコンテナでは、クイックソートの利点はありません。
1。リンクリストでソートをマージします。追加のメモリは必要ありません。 2.クイックソートの要素へのアクセスがシーケンシャルではない(メモリ内)

1
minorlogic

それを言うのは難しいです。MergeSortの最悪はn(log2n)-n + 1です、nが2 ^ kに等しいならば正確です(私はすでにこれを証明しました)。そして、どんなnについても、(n lg n - n +) 1)および(n lg n + n + O(lg n))ただし、quickSortの場合、nlog2nが最適です(nは2 ^ kに等しい)。nが無限大の場合、MergesortをquickSortで除算すると1になります。 MergeSortの最悪のケースがQuickSortの最善のケースよりも優れているかのようですが、なぜクイックソートを使用するのですか?ただし、MergeSortは適切に配置されていないため、2nのスペースを必要とします。アルゴリズムの分析には含めないでください。一言で言えば、MergeSortは理論上のクイックソートよりも本当に速いですが、実際にはメモリのスペース、配列コピーのコストを考慮する必要があります。マージはクイックソートよりも遅くなります。ランダムクラスでJavaに1000000桁を与えた実験で、マージソートで2610ms、クイックソートで1370msかかりました。

1
Peter

すべてが平等で、私はほとんどの人が最も便利に利用できるものは何でも使うことを期待します、そしてそれはqsort(3)になる傾向があります。それ以外のクイックソートは、マージソートがリストの一般的な選択であるのと同じように、アレイ上で非常に高速であることが知られています。

私が思っているのは、 基数 やバケツソートを見ることがめったにないのです。それらはO(n)です、少なくともリンクされたリストでは、キーを序数に変換する方法がすべてです。 (ひもとフロートはうまく働きます。)

その理由は、コンピュータサイエンスがどのように教えられているかによると私は考えています。アルゴリズム解析の講師に、O(n log(n))よりも速くソートすることが本当に可能であることを証明しなければなりませんでした。 (彼はO(n log(n))より速く比較ソートできないという証明を持っていました。これは真実です。)

他のニュースでは、浮動小数点数は整数としてソートすることができますが、後で負の数を変える必要があります。

編集:実際には、ここで整数としてフロートをソートするためのさらに悪質な方法です: http://www.stereopsis.com/radix.html 。実際に使用しているソートアルゴリズムに関係なく、ビット反転トリックを使用できます。

1
Anders Eurenius

時間と空間の両方の複雑さを考慮してください。マージソートの場合:時間の複雑さ:O(nlogn)、スペースの複雑さ:O(nlogn)

クイックソートの場合:時間の複雑さ:O(n ^ 2)、スペースの複雑さ:O(n)

今、彼らは両方ともそれぞれ1シーンで勝ちます。ただし、ランダムピボットを使用すると、ほとんどの場合、クイックソートの時間の複雑さをO(nlogn)に減らすことができます。

したがって、MergeソートよりもQuickソートが多くのアプリケーションで好まれています。

0
pankaj

クイックソートはインプレースソートアルゴリズムなので、配列に適しています。一方、マージソートはO(N)の追加の記憶域を必要とし、リンクリストに適しています。

配列とは異なり、お気に入りリストではO(1) spaceとO(1) timeの中間に項目を挿入できます。したがって、マージソートのマージ操作はなしで実装できます。余分なスペースただし、配列に余分なスペースを割り当てたり割り当て解除したりすると、マージソートの実行時間に悪影響があります。ランダムにメモリにアクセスすることなく、データがシーケンシャルにアクセスされるため、マージソートもリンクリストを優先します。

一方、クイックソートはランダムなメモリアクセスを多く必要とし、配列を使用するとリンクリストで要求されるように移動することなく直接メモリにアクセスできます。配列がメモリに連続して格納されているため、配列に使用した場合のクイックソートも参照の局所性が良好です。

どちらのソートアルゴリズムでも平均的な複雑度はO(NlogN)ですが、通常の業務ではストレージにアレイを使用するため、クイックソートが最適なアルゴリズムとなります。

編集:私はちょうどマージソートの最悪/ベスト/平均ケースが常にnlognであることを発見したが、クイックソートはn2(エレメントが既にソートされている場合の最悪ケース)からnlogn(ピボットが常に2つに分割する場合のベストケース)まで変わり得る。半分)。

0
Saad