Javascript es6映射和设置复杂性,v8实现
在v8实现中,检索/查找是O(1),这是一个公平的假设吗 (我知道标准并不能保证这一点) 在v8实现中,检索/查找是O(1),这是一个公平的假设吗 对。V8使用哈希表的一个变体,对于这些操作,哈希表通常具有Javascript es6映射和设置复杂性,v8实现,javascript,ecmascript-6,set,complexity-theory,v8,Javascript,Ecmascript 6,Set,Complexity Theory,V8,在v8实现中,检索/查找是O(1),这是一个公平的假设吗 (我知道标准并不能保证这一点) 在v8实现中,检索/查找是O(1),这是一个公平的假设吗 对。V8使用哈希表的一个变体,对于这些操作,哈希表通常具有O(1)复杂性 有关详细信息,您可能想看看OrderedHashTable是基于什么实现的。因为人们不想把兔子洞挖得太深: 1:我们可以假设好的哈希表实现实际上具有O(1)时间复杂性。 2:这里有一个由V8团队发布的博客,解释了如何在Map、Set、WeakSet和WeakMap的哈希表实现上
O(1)
复杂性
有关详细信息,您可能想看看OrderedHashTable是基于什么实现的。因为人们不想把兔子洞挖得太深: 1:我们可以假设好的哈希表实现实际上具有O(1)时间复杂性。
2:这里有一个由V8团队发布的博客,解释了如何在
Map
、Set
、WeakSet
和WeakMap
的哈希表实现上进行一些内存优化:
基于1和2:V8的Set和Map的get
&Set
&add
&的时间复杂度实际上是O(1)。让Map=newmap();
设obj={};
常量基准映射集=大小=>{
控制台时间(“基准映射集”);
for(设i=0;i{
console.time(“benchMarkMapGet”);
for(设i=0;i{
控制台时间(“基准测试对象集”);
for(设i=0;i{
控制台时间(“基准对象”);
for(设i=0;i
基准地图集:382.935ms
基准对象集:76.077ms
基准MapGet:125.478ms
基准目标集:2.764ms
基准地图集:373.172ms
基准OBJSET:77.192ms
基准地图获取:123.035ms
benchMarkObjGet:2.638ms
原来的问题已经得到了回答,但是O(1)并没有告诉我们实现的效率有多高
首先,我们需要了解哈希表的哪些变体用于映射。“经典”哈希表不会这样做,因为它们不提供任何迭代顺序保证,而ES6规范要求按迭代顺序插入。所以,V8中的地图是建立在所谓的。该思想与经典算法类似,但bucket还有另一层间接寻址,所有条目都插入并存储在固定大小的连续数组中。确定性哈希表算法确实保证了基本操作的时间复杂性为O(1),如set
或get
接下来,我们需要知道哈希表的初始大小、负载因子以及它如何(以及何时)增长/收缩。简单的回答是:初始大小为4,负载系数为2,表(即映射)在达到其容量时立即增大x2,在删除的条目超过1/2时立即缩小
让我们考虑最坏的情况,当表有N个条目(满)时,所有条目都属于单个桶,所需的条目位于尾部。在这种情况下,查找需要在链元素中移动N次
另一方面,在表已满但每个bucket有2个条目的最佳情况下,查找最多需要2次移动
众所周知,虽然哈希表中的单个操作“便宜”,但重新灰化却不便宜。重新哈希具有O(N)时间复杂度,需要在堆上分配新的哈希表。此外,必要时,作为插入或删除操作的一部分执行重新灰化。因此,例如,map.set()
调用可能比您预期的更昂贵。幸运的是,再灰化是一种相对少见的操作
除此之外,诸如内存布局或哈希函数之类的细节也很重要,但我不打算在这里讨论这些细节。如果你想知道V8地图在引擎盖下是如何工作的,你可以找到更多细节。不久前,我对这个话题很感兴趣,并试图以可读的方式分享我的发现。我们为什么不进行测试呢
var size_1=1000,
尺寸2=1000000,
map_sm=新映射(数组.from({length:size_1},(u,i)=>[++i,i]),
map_lg=新映射(数组.from({length:size_2},(u,i)=>[++i,i]),
i=尺寸_1,
j=尺寸_2,
s
s=性能。现在();
而(i)map_sm.get(i--);;
log(`Size${Size_1}map返回平均值为${(performance.now()-s)/Size_1}ms`)的项;
s=性能。现在();
而(j)map_lg.get(j--);
log(`Size${Size_2}map返回一个平均值为${(performance.now()-s)/Size_2}ms`)的项代码>平均值?或者最坏的情况?顺便说一句,@Oriol这两个标准都很想知道。不确定V8使用的是什么,但其中提到了哈希表作为一种可能性。平均时间为常数,最坏情况下为线性。另一个很好的答案是对其进行扩展,V8中的Map和Set最近在JavaScript中重新实现。这在V8中很常见,在JavaScript中实现新功能可以让JIT(曲轴/涡轮风扇)优化运行时代码。@DiegoPino:谢谢。我不知何故认为,OrderedHashTable
实现仍然是最新的,因为我在……中找到了它,看起来实现已经从src/collections.js
移动到了src/builtins/builtins-collections-gen.cc,这是因为Map类是通过插入排序的。
let map = new Map();
let obj = {};
const benchMarkMapSet = size => {
console.time("benchMarkMapSet");
for (let i = 0; i < size; i++) {
map.set(i, i);
}
console.timeEnd("benchMarkMapSet");
};
const benchMarkMapGet = size => {
console.time("benchMarkMapGet");
for (let i = 0; i < size; i++) {
let x = map.get(i);
}
console.timeEnd("benchMarkMapGet");
};
const benchMarkObjSet = size => {
console.time("benchMarkObjSet");
for (let i = 0; i < size; i++) {
obj[i] = i;
}
console.timeEnd("benchMarkObjSet");
};
const benchMarkObjGet = size => {
console.time("benchMarkObjGet");
for (let i = 0; i < size; i++) {
let x = obj[i];
}
console.timeEnd("benchMarkObjGet");
};
let size = 2e6;
benchMarkMapSet(size);
benchMarkObjSet(size);
benchMarkMapGet(size);
benchMarkObjGet(size);