web-dev-qa-db-ja.com

ティムソートとクイックソートの比較

ティムソート(ウィキペディアによれば)のパフォーマンスがはるかに優れているように見えるときに、クイックソートが全体的な最速のソートアルゴリズムであるとよく耳にするのはなぜですか? Googleはどんな種類の比較も明らかにしなかったようだ。

55
chenglou

TimSortは高度に最適化されたマージソートであり、古いマージソートよりも安定して高速です。

クイックソートと比較すると、次の2つの利点があります。

  1. ほぼソートされたデータシーケンス(リバースソートされたデータを含む)の場合、信じられないほど高速です。
  2. 最悪の場合はまだO(N * LOG(N))です。

正直に言うと、#1が利点であるとは思いませんが、私は感銘を受けました。

QuickSortの利点は次のとおりです

  1. QuickSortは非常にシンプルで、高度に調整された実装でさえ、20行以内にそのpseduoコードを書き留めることができます。
  2. QuickSortはほとんどの場合最速です。
  3. メモリ消費はLOG(N)です。

現在、Java 7 SDKはtimsortと新しいクイックソートバリアントを実装しています。つまり、Dual Pivot QuickSort。

安定したソートが必要な場合は、timsortを試してください。そうでない場合は、クイックソートから始めてください。

37
Chang

多かれ少なかれ、それは Timsort がハイブリッドソートアルゴリズムであるという事実に関係しています。つまり、使用する2つの基本的なソート(マージソートと挿入ソート)は、多くの種類のデータでは Quicksort よりも劣っていますが、Timsortはそうすることが有利な場合にのみ使用します。

Patrick87 のように、少し深いレベルでは、クイックソートは最悪の場合のO(n2)アルゴリズム。適切なピボットを選択することは hard ではありませんが、O(n log n)クイックソートを保証するには、平均してソートが一般に遅くなるという犠牲が伴います。

Timsortの詳細については、 this answer とリンクされたブログ投稿を参照してください。基本的に、ほとんどのデータがすでに部分的にソートされていることを前提とし、mergesortを使用した効率的なマージを可能にするソート済みデータの「実行」を構築します。

25
brc

一般的に言えば、クイックソートはプリミティブ配列に最適なアルゴリズムです。これは、メモリの局所性とキャッシュによるものです。

JDK7は、オブジェクト配列にTimSortを使用します。オブジェクト配列はオブジェクト参照のみを保持します。オブジェクト自体はヒープに格納されます。オブジェクトを比較するには、オブジェクトをヒープから読み取る必要があります。これは、あるオブジェクトのヒープの一部から読み取り、次にヒープの別の部分からランダムにオブジェクトを読み取るようなものです。多くのキャッシュミスが発生します。この理由で、メモリの局所性はもはや重要ではないと思います。これが、JDKがプリミティブ配列の場合にオブジェクト配列にTimSortのみを使用する理由です。

これは私の推測です。

17
jason zhang

私のマシンのベンチマーク番号(i7-6700 CPU、3.4GHz、Ubuntu 16.04、gcc 5.4.0、パラメーター:SIZE = 100000、RUNS = 3):

$ ./demo 
Running tests
stdlib qsort time:                 12246.33 us per iteration
##quick sort time:                  5822.00 us per iteration
merge sort time:                    8244.33 us per iteration
...    
##tim sort time:                    7695.33 us per iteration
in-place merge sort time:           6788.00 us per iteration    
sqrt sort time:                     7289.33 us per iteration    
...
grail sort dyn buffer sort time:    7856.67 us per iteration

ベンチマークは、Swensonの sort プロジェクトから来ています。このプロジェクトでは、Cでいくつかのソートアルゴリズムを実装しています。おそらく代表になりますが、私はそれらを調査していません。

だからあなたは本当に言うことができません。ベンチマークの数値は、最大で2年間しか関連性が保たれないため、繰り返します。おそらく、ティムソートは質問が尋ねられた2011年にqsortを打ち負かしましたが、時代は変わりました。または、qsortは常に最速でしたが、timsortは非ランダムデータでそれを破りました。または、スウェンソンのコードはそれほど良くなく、より良いプログラマーはティムソートの好意で流れを変えるでしょう。または、コードをコンパイルするときに正しいCFLAGSを使用しなかったかもしれません。または...ポイントを取得します。

5

Javaは整数配列と二重配列にダブルピボットクイックソートを使用するため、コードフォースプログラミングの競争では標準のJavaソートを使用できません。したがって、O(n ^ 2)時間を必要とする配列が存在します走る。また、一部のテストデータは多くの場合これらの配列で構成されているため、プログラムに時間がかかりすぎて失敗します。そのため、代わりに独自のmergeSortに切り替える必要があります。ティムソートアルゴリズムでは発生しません。

0
user3814357