为什么Javascript==/==字符串相等有时具有恒定的时间复杂度,有时具有线性时间复杂度?
在我发现常见/最新的Javascript实现使用字符串Interning来实现性能提升()之后,我认为字符串的为什么Javascript==/==字符串相等有时具有恒定的时间复杂度,有时具有线性时间复杂度?,javascript,string,performance,time-complexity,string-interning,Javascript,String,Performance,Time Complexity,String Interning,在我发现常见/最新的Javascript实现使用字符串Interning来实现性能提升()之后,我认为字符串的==将获得恒定的O(1)时间。所以我对这个问题的回答是错误的: 因为根据这个问题的OP,它是O(N),所以将字符串输入加倍会使相等所需的时间加倍。他没有提供任何jsPerf,所以需要更多的调查 所以我使用字符串实习的场景是: var str1=“stringwithmillionchars”//存储在地址51242中 var str2=“stringwithmillionchars”/
==
将获得恒定的O(1)时间。所以我对这个问题的回答是错误的:
因为根据这个问题的OP,它是O(N),所以将字符串输入加倍会使相等所需的时间加倍。他没有提供任何jsPerf,所以需要更多的调查
所以我使用字符串实习的场景是:
var str1=“stringwithmillionchars”//存储在地址51242中
var str2=“stringwithmillionchars”//存储在地址12313中
“stringwithmillionchars”将存储一次,比如说存储在内存的地址201012中
str1和str2都指向这个地址201012。然后可以通过某种散列来确定该地址,以映射到内存中的特定位置
所以当你做
“stringwithmillionchars”==“stringwithmillionchars”
看起来像
getContentOfAddress(51242)==getContentOfAddress(12313)
或201012==201012
这需要O(1)/恒定时间
JSPerfs/性能更新:
即使字符串长16倍,JSPerf似乎也显示常量时间??请看一看:
可能上面的字符串太小:
这可能显示线性时间(感谢sergioFC),字符串是用循环构建的。我尝试不使用函数-仍然是线性时间/我稍微改变了一下
根据(sergioFC制作的12MB文件),当您有一个字符串并且已经在引号中赋值时,无论t1和t2有多大(例如5930496个字符),都需要0-1ms/瞬间
似乎当您使用for循环或函数构建字符串时,该字符串就不会被插入。因此,只有当您直接分配一个带引号的字符串时,才会发生实习,如var str=“test”代码>根据,即使要比较的对象的类型是字符串,也会检查所有字符是否相等
如果Type(x)
是字符串,则返回true
如果x
和y
是完全相同的字符序列(相同的长度和相应位置的相同字符)否则,返回false
实习严格地说是一种实施,是为了提高绩效。语言标准在这方面没有任何规定。因此,是否插入字符串取决于规范的实现者。首先,最好看到一个JSPerf测试,它演示了字符串大小加倍会使执行时间加倍的说法
接下来,让我们认为这是理所当然的。这是我的理论(未经证实,未经检验,可能与现实无关)
不管引用了多少数据,比较两个内存地址都很快。但你必须先实习。如果代码中有
var a = "1234";
var b = "1234";
然后引擎首先必须理解这两个字符串是相同的,并且可以指向相同的地址。因此,至少有一次,这些字符串必须进行充分比较。因此,基本上有以下几种选择:
- 在解析代码时,引擎直接比较和插入字符串。在这种情况下,equals字符串应该获得相同的地址
- 引擎可能会说“这些字符串是两个大字符串,我不想实习它们”,并且有两个副本
- 发动机可能会在以后对这些管柱进行实习
在后两种情况下,字符串比较将影响测试结果。在最后一种情况下,即使字符串最终被插入
但正如我所写,一个狂野的理论,对于理论的圣人来说。首先,我希望看到一些JSPerf。基于字符串a和b的所有性能测试(参见原始帖子),操作a===b
需要:
- 恒定时间O(1)如果字符串被插入。从示例中可以看出,实习似乎只发生在直接指定的字符串中,如
var str=“test”如果您使用for循环或函数的串联来构建它,则不会使用code>
- 线性时间O(N)因为在所有其他情况下,首先比较两个字符串的长度。如果它是相等的,那么我们就可以进行逐个字符的比较。除此之外,它们当然是不平等的。N是字符串的长度
我认为这是因为===运算符仅在比较对象时比较内存地址(类似于Java)。但是“某物”不是对象,它的类型是内置字符串。与比较数字相同,var a=2;var b=2;,如果你做a==b,你就不是在比较对象或内存地址。我知道你可以做varstr=newstring(“test”)代码>但我也不知道其中的含义。即使这样做,typeof str也将是“string”,而不是object。为了不破坏更多的浏览器,我已经删除了fiddle。我觉得它们太小了。重要提示:我刚刚测试了两个相等字符串的比较,其中包含5930496个字符,这些字符是使用var s1='…'构造的;变量s2='…';tooks 0ms,而char-tooks 20ms构造的相同字符串的比较。不知道,我不熟悉实习。字符串太长,文件大小为12MB。我将把它上传到Dropbox并用链接更新这个评论。谢谢。您能想出一个原因,为什么这是一个比将字符串作为两个对象处理更好的选择吗?有这样的开销吗?我看不出这是如何迫使引擎实际进行完整的字符串比较的。如果两个变量指向内存中某个地方保存的同一字符串,则它们将满足此要求。@michailidis Interning严格来说是一种实现,用于提高性能。