密钥集合(Set,Map,WeakSet和WeakMap)的ES6规范提供了什么时间复杂度(以大O表示法)?
我的期望,我希望大多数开发人员都希望规范和实现使用widely accepted高性能算法,在这种情况下Set.prototype.has
,add
和delete
在一般情况下都是O(1)。 Map
和Weak–
等价物相同。
对我来说,实施的时间复杂性是否是强制性的,这一点并不完全清楚。在ECMAScript 2015 Language Specification - 6th Edition — 23.2 Set Objects。
除非我误解它(我当然很可能),看起来ECMA规范要求实现(例如Set.prototype.has
)使用线性时间( O(n))算法。令我极为惊讶的是,规范不会强制要求甚至不允许使用更高性能的算法,我会非常感兴趣地解释为什么会出现这种情况。
答案 0 :(得分:38)
从that very paragraph链接到:
必须使用[机制]实现设置对象,这些机制平均提供对集合中元素数量的次线性访问时间。
您会为Maps,WeakMaps和WeakSets找到相同的句子。
看起来ECMA规范要求实现(例如Set.prototype.has)使用线性时间(
O(n)
)算法。
没有
此
Set
对象规范中使用的数据结构仅用于描述Set对象所需的可观察语义。它并不是一个可行的实施模型。
可观察的语义主要与可预测的迭代顺序(仍然可以是implemented efficient and fast)相关。规范确实期望实现使用散列表或类似于常量访问的东西,尽管也允许树(具有对数访问复杂性)。
答案 1 :(得分:6)
对于任何好奇的人,我做了一个非常快速的基准测试:
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 w / 16G RAM)
benchmarkMap: 189.120ms
benchmarkHash: 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