2011-08-28 9 views
18

少しテストをしたところ、array.sort(function(a, b) { return a - b; });はJavaScriptのarray.sort();よりずっと高速です。JavaScriptの2番目のパラメータでソートするのが速い

結果はかなり衝撃的で、IE9では約1.7倍、FF7では約1.6倍、Chromeでは約6.7倍の速さでした。

また、自分でquicksortをJSで実装すると、上記の両方の方法よりも速いことがわかりました。 (2つの異なる実装で、1つはパラメータとして比較関数を受け取り、もう1つは高速です)。

合理的な説明はありますか?

EDIT:私の実装:

ませんコンペアラー:比較演算子で

function quickSort(array, from, to) { 
    if(typeof from === 'undefined') { 
     from = 0; 
     to = array.length - 1; 
    } 
    else if(typeof to === 'undefined') { 
     to = array.length - 1; 
    } 

    if(to - from < 1) { 
     return; 
    } 

    var i = from, pivot = to, t; 

    while(i < pivot) { 
     if(array[i] > array[pivot]) { 
      t = array[i]; 
      array[i] = array[pivot - 1]; 
      array[pivot - 1] = array[pivot]; 
      array[pivot] = t; 
      pivot--; 
     } 
     else { 
      i++; 
     } 
    } 

    quickSort(array, from, pivot - 1); 
    quickSort(array, pivot + 1, to); 
} 

:フェリックス・キングなど

まず、:

function quickSortFunc(array, sortfunc, from, to) { 
    if(typeof from === 'undefined') { 
     from = 0; 
     to = array.length - 1; 
    } 
    else if(typeof to === 'undefined') { 
     to = array.length - 1; 
    } 

    if(to - from < 1) { 
     return; 
    } 

    var i = from, pivot = to, t; 

    while(i < pivot) { 
     if(sortfunc(array[i], array[pivot]) > 0) { 
      t = array[i]; 
      array[i] = array[pivot - 1]; 
      array[pivot - 1] = array[pivot]; 
      array[pivot] = t; 
      pivot--; 
     } 
     else { 
      i++; 
     } 
    } 

    quickSortFunc(array, sortfunc, from, pivot - 1); 
    quickSortFunc(array, sortfunc, pivot + 1, to); 
} 
+0

それはソート機能が平均値から実行されている可能性です。あなたが使ったアレイの大きさはどれくらいですか? – Matt

+3

"ノーマル"ソートは要素の文字列表現に作用します。それは可能性のあるオーバーヘッドかもしれません。 –

+0

Matt、私は100,1000,10000、および100000要素の配列でそれをテストしました。比較演算子と私の実装は比較子を持つネイティブ実装よりも速かった理由 フェリックスは、私もその2については、それはまだ説明していません。 –

答えて

1

遊びに来て二つの要因がありますネイティブソートメソッドは、各配列メンバを文字列に変換します比較する前に。 function(a, b) { return a - b; }を使用すると、すべての(またはほとんどの)配列メンバが数値であれば高速になります。

第2に、ソートアルゴリズムはimplementation dependentです。既にソートされた配列に新しい要素を挿入すると、あなたが知っているかどうか分からないかもしれません。 WebKitが代わりに選択ソートを実装することになったのはこのためです。

しかし、恐れていない、助けに近いです!既に誰かforked WebKit to fix this

0

多くの理由があります。変数型をチェックする必要はなく、そのうちの1つだけです。そして、あなたの実装はオプティマイザを幸せにします。それは密な配列で動作し、数字だけで動作し、変数は範囲が広く、再利用されます。いいえ、いいえ、評価なし、魔法の変数、プロパティ、関数、タイプはありません。それはうまく最適化されます。

しかし、タイプ依存型の配列に依存しない配列メソッド(例えば、reverse())を実装しようとすると、独自の実装が高速になることがあります。少なくとも私のものです。

なぜですか?

JavaScriptは今日、特に同じ種類のもの(数字、文字列、同じ形状のオブジェクトでさえ複雑(複雑です))でループや繰り返し操作が頻繁に最適化されています。極端な場合、ランタイムは関数をインライン展開し、変数型チェックをスキップします。また、Chromeの場合は、ループがCほど高速になるように番号を保持することさえあります。

Wow。

しかし、これらの最適化は近年でのみ有効です。現時点では、ネイティブ関数はユーザーコードほど最適化されていません。ユーザーコードと同じくらい動的な最適化は行われません。

そこに、私はそれを言った。

現在のところ、ユーザーコードは、プログラマがその中のどのデータフローを知っているので、より速く実行しても、ネイティブ実装で実行することができます。しかしこれは一時的なものになる可能性があります

私はここで停止し、あなたがあなた自身の配列のライブラリーを作成するかどうかを決めてもらおう。 ;)

+0

それは真実のほんの一部です。ほとんどのArrayメソッドは意図的に汎用的に定義されているので、配列ではないオブジェクトに対しても動作する必要があることに注意してください。あなたの実装が速ければ、おそらくあなたは狂った特殊なケースを忘れたからでしょう。 ({: '3' '2'、 '2'、3 ''、長さ: '3.5'、リンゴ 'オレンジ'}) 'Array.prototype.reverse.call例えば'あるいは 'のvar A = [] ; a [1] = 1; a.reverse()。hasOwnProperty(1)// false'。これらは、ブラウザベンダーが最適化してはいけないことです。それ以外の場合、jQueryは別のチケットで作業する必要があります; – user123444555621

+0

@ Pumbaa80:仕様をチェックしただけですが、この例の極端な内容は確認できませんでした。仕様では長さをとり、符号なしのintにしてから、0からlength-1に逆順に開始します。ここの落とし穴は何か分かりますか? – Sheepy

+0

私はあなたの実装を見ていないが、[鉱山は(特別な場合を考慮して)](http://jsperf.com/array-reverseは)間違いなく遅いです。 – user123444555621

0

これは非常に野生の推測ですが、パフォーマンスヒットは一度したがって、各検索のデフォルトの機能を検索する...渡された属性が空白またはnullであるかどうかをチェックする、ネイティブのソートのために発生する(代わりの可能性)...

それが本当ならば解決できると誤解最適化の問題である可能性があり... Firefoxのdevにうまくいけば、誰かがこれを答えることができます:)

関連する問題