コレクションのJavascriptES6計算/時間計算量


89

キー付きコレクション(Set、Map、WeakSet、およびWeakMap)のES6仕様によって(big-O表記で)どのくらいの時間計算量が提供されますか?

私の期待、およびIは、ほとんどの開発者の仕様や実装が使用することであることを期待する、広く受け入れられている場合にパフォーマンスアルゴリズムSet.prototype.hasadd及びdelete平均場合の全てであるO(1)にします。MapおよびWeak–同等のものについても同じです。

実装の時間計算量が義務付けられているかどうかは、私には完全には明らかではありません。たとえば、ECMAScript 2015言語仕様-第6版-23.2オブジェクトの設定などです。

私がそれを誤解しない限り(そして私がそうすることは確かに非常に可能です)、ECMA仕様は実装(例えばSet.prototype.has)が線形時間(O(n))アルゴリズムを使用することを義務付けているように見えます。より高性能なアルゴリズムが仕様で義務付けられておらず、許可さえされていないことは非常に驚くべきことであり、なぜそうなるのかについての説明に非常に興味があります。


2
すべてのO(1)アルゴリズムもO(n)であるため、仕様のパフォーマンスが低い実装を取り入れても害はありません。おそらく、パフォーマンスの低い実装は、必要なコード/スペースがはるかに少ないため、リソースが制約されているシステムに関心がある可能性があります。
artur grzesiak 2015年

@arturgrzesiakキー付きコレクションのO(1)パフォーマンスは、通常、O(1)ハッシュとO(n)衝突バケットを使用して実現されます。O(n)の最悪のケースは、ほとんどの実用的な目的では天文学的にまれです。これらの手法のスペースの複雑さは、一般にO(n)です。
ブライアンM.ハント2015年

1
「セットオブジェクトは、ハッシュテーブルまたはコレクション内の要素の数に対して平均して劣線形のアクセス時間を提供する他のメカニズムのいずれかを使用して実装する必要があります。」-まさにそのページから。
georg 2015年

回答:


61

、非常に段落あなたにリンクされています:

セットオブジェクトは、平均して、コレクション内の要素の数に対して劣線形であるアクセス時間を提供する[メカニズム]を使用して実装する必要があります。

MapsWeakMapsWeakSetsにも同じ文があります

ECMA仕様では、実装(Set.prototype.hasなど)で線形時間(O(n))アルゴリズムを使用することが義務付けられているようです。

番号:

このSetオブジェクト仕様で使用されるデータ構造は、Setオブジェクトの必要な監視可能なセマンティクスを説明することのみを目的としています。これは、実行可能な実装モデルを意図したものではありません。

観察可能なセマンティクスは、主に予測可能な反復順序に関連しています(これは依然として効率的かつ高速に実装できます)。仕様では、ツリー(対数アクセスの複雑さ)も許可されていますが、実装ではハッシュテーブルなどの定数アクセスを使用することが実際に期待されています。


2
それを選んでくれてありがとう。その段落にたどり着くまでに、私の目は釉薬をかけていたに違いありません。:)では、O(log(n))またはO(1)のいずれかであるが、それ以外の場合は必須ではないアルゴリズム(O(n)の下にある場合)?
ブライアンM.ハント

1
@ BrianM.Hunt:正解です。
ベルギ2015年

32

好奇心旺盛な人のために、私は非常に簡単なベンチマークを行いました。

const benchmarkMap = size => {
  console.time('benchmarkMap');
  var map = new Map();
  for (var i = 0; i < size; i++) map.set(i, i);
  for (var i = 0; i < size; i++) var x = map.get(i);
  console.timeEnd('benchmarkMap');
}

const benchmarkObj = size => {
  console.time('benchmarkObj');
  var obj = {};
  for (var i = 0; i < size; i++) obj[i] = i;
  for (var i = 0; i < size; i++) var x = obj[i];
  console.timeEnd('benchmarkObj');
}

var size = 1000000;

benchmarkMap(size);
benchmarkObj(size);

これを数回実行すると、次の結果が得られました。

(2017 MacBook Pro、2.5 GHz i7、16G RAM)

benchmarkMap: 189.120ms
benchmarkObj: 44.214ms

benchmarkMap: 200.817ms
benchmarkObj: 38.963ms

benchmarkMap: 187.968ms
benchmarkObj: 41.633ms

benchmarkMap: 186.533ms
benchmarkObj: 35.850ms

benchmarkMap: 187.339ms
benchmarkObj: 44.515ms

3
@domdambrogiaは、あなたが得ることから設定を析出する場合、私は得る:マップセット= 124、地図= 40、オブジェクトの設定= 26を取得し、オブジェクトを取得= 1(これらは、比は、ありませんMS)
AJP

@AJP私は考えていませんでした、それらの統計でもそれを分解しました。ご意見ありがとうございます、それは良い貢献です。少し時間があれば、それを答えに追加できるかどうかを確認します。ありがとう!
domdambrogia

課題をリーディングから分離して、どちらがリーディングの方が速いかを学ぶことも興味深いでしょう。
fernandopasik

3
2017MacBookPro、2.5 GHz i7、16G RAM」-ええと、それはすばらしいことですが、どのjavascriptエンジンをベンチマークしましたか?
ベルギ

1
興味深いことに、追加delete操作と操作が混在していると、Mapパフォーマンスが大幅に向上します。jsfiddle.net/23hrp0eq
Jorjon
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.