我在阅读有关数组操作的运行时复杂性的文章时了解到...
Array.push() 以常数 和Array.unshift() 以线性 时间运行,用于稀疏由类似哈希表的数据结构实现的数组 [3] .现在我想知道 push 和 unshift 在 dense arrays 上是否具有相同的常数和线性时间复杂度. Firefox/Spidermonkey 中的实验结果证实:
现在我的问题:
unshift 没有使用类似于 push 的constant 运行时实现(例如保持索引偏移量;类似于 perl arrays ) ?最佳答案
要理解这一点,需要了解堆栈(在 JavaScript 中为数组)在计算机科学中是如何设计的,以及如何在您的 RAM/内存中表示的。如果您创建一个堆栈(一个数组),本质上您是在告诉系统在内存中为一个最终可以增长的堆栈分配一个空间。
现在,每次您添加到该堆栈(使用 push)时,它都会添加到该堆栈的end。最终系统发现 Stack 不够大,所以它在内存中分配了一个新空间 oldstack.length*1.5-1 并将旧信息复制到新空间。这就是你的图表中跳跃/抖动的原因,否则看起来平坦/线性。这种行为也是为什么你总是应该用 var a=new Array(1000) 初始化一个预定义大小(如果你知道)的数组/堆栈,这样系统就不需要“新分配内存并复制过来”。
考虑到unshift,它看起来和push很相似。它只是将它添加到列表的开始,对吗?但是,尽管这种差异看起来不屑一顾,但它非常大!正如推送所解释的那样,当大小用完时,最终会有一个“分配内存并复制”。对于 unshift,它希望向 start 添加一些内容。但是那里已经有东西了。所以它必须将位置 N 的元素移动到位置 N+1,N1 到 N1+1,N2 到 N2 +1 等。因为效率很低,它实际上只是重新分配内存,添加新元素,然后将旧堆栈复制到新堆栈。这就是您的图表看起来更像是二次方甚至是轻微指数的原因。
总结;
push 添加到end,很少需要重新分配内存+复制。
unshift 添加到start 并且总是 需要重新分配内存并复制数据
/edit:关于你的问题为什么不能用“移动索引”解决这个问题是当你交替使用 unshift 和 push 时的问题,你需要多个“移动索引”和密集计算来找出那个元素在哪里索引 2 实际上驻留在内存中。但 Stack 背后的想法是具有 O(1) 的复杂性。
还有许多其他数据结构具有此类属性(和更多功能),但在速度、内存使用等方面有所折衷。其中一些数据结构是 Vector,Double-Linked -List、SkipList 甚至是 Binary Search Tree,具体取决于您的要求
Here is a good resource explaining datastructures and some differences/advancements between them
关于javascript - Array.push 与 Array.unshift 的性能对比,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44031591/
我怎样才能完成http://php.net/manual/en/function.call-user-func-array.php在ruby中?所以我可以这样做:classAppdeffoo(a,b)putsa+benddefbarargs=[1,2]App.send(:foo,args)#doesn'tworkApp.send(:foo,args[0],args[1])#doeswork,butdoesnotscaleendend 最佳答案 尝试分解数组App.send(:foo,*args)
通过rubykoans.com,我在about_array_assignment.rb中遇到了这两段代码你怎么知道第一个是非并行赋值,第二个是一个变量的并行赋值?在我看来,除了命名差异之外,代码几乎完全相同。4deftest_non_parallel_assignment5names=["John","Smith"]6assert_equal["John","Smith"],names7end45deftest_parallel_assignment_with_one_variable46first_name,=["John","Smith"]47assert_equal'John
这个问题在这里已经有了答案:Arraysmisbehaving(1个回答)关闭6年前。是否应该这样,即我误解了,还是错误?a=Array.new(3,Array.new(3))a[1].fill('g')=>[["g","g","g"],["g","g","g"],["g","g","g"]]它不应该导致:=>[[nil,nil,nil],["g","g","g"],[nil,nil,nil]]
我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的
我正在使用Rails3.2.3和Ruby1.9.3p0。我发现我经常需要确定某个字符串是否出现在选项列表中。看来我可以使用Ruby数组.includemethod:或正则表达式equals-tildematchshorthand用竖线分隔选项:就性能而言,一个比另一个好吗?还有更好的方法吗? 最佳答案 总结:Array#include?包含String元素,在接受和拒绝输入时均胜出,对于您的示例只有三个可接受的值。对于要检查的更大的集合,看起来Set#include?和String元素可能会获胜。如何测试我们应该根据经验对此进行测试
我正在使用Ruby解决一些ProjectEuler问题,特别是这里我要讨论的问题25(Fibonacci数列中包含1000位数字的第一项的索引是多少?)。起初,我使用的是Ruby2.2.3,我将问题编码为:number=3a=1b=2whileb.to_s.length但后来我发现2.4.2版本有一个名为digits的方法,这正是我需要的。我转换为代码:whileb.digits.length当我比较这两种方法时,digits慢得多。时间./025/problem025.rb0.13s用户0.02s系统80%cpu0.190总计./025/problem025.rb2.19s用户0.0
我正在寻找一个用ruby演示计时器的在线示例,并发现了下面的代码。它按预期工作,但这个简单的程序使用30Mo内存(如Windows任务管理器中所示)和太多CPU有意义吗?非常感谢deftime_blockstart_time=Time.nowThread.new{yield}Time.now-start_timeenddefrepeat_every(seconds)whiletruedotime_spent=time_block{yield}#Tohandle-vesleepinteravalsleep(seconds-time_spent)iftime_spent
如thisanswer中所述,Array.new(size,object)创建一个数组,其中size引用相同的object。hash=Hash.newa=Array.new(2,hash)a[0]['cat']='feline'a#=>[{"cat"=>"feline"},{"cat"=>"feline"}]a[1]['cat']='Felix'a#=>[{"cat"=>"Felix"},{"cat"=>"Felix"}]为什么Ruby会这样做,而不是对object进行dup或clone? 最佳答案 因为那是thedocumenta
如果用户是所有者,我有一个条件来检查说删除和文章。delete_articleifuser.owner?另一种方式是user.owner?&&delete_article选择它有什么好处还是它只是一种写作风格 最佳答案 性能不太可能成为该声明的问题。第一个要好得多-它更容易阅读。您future的自己和其他将开始编写代码的人会为此感谢您。 关于ruby-on-rails-如果条件与&&,是否有任何性能提升,我们在StackOverflow上找到一个类似的问题:
我发现ruby加载路径是一个数组,很多项目都是这样使用的:$:.unshift(File.expand_path("../../lib",__FILE__))可以将本地文件添加到ruby路径数组的前面,方便我们require或者load。所以,我希望知道为什么我们不使用push将文件添加到数组的末尾? 最佳答案 假设您有一个“date.rb”文件(为什么不呢)并且您想要加载这个文件,而不是标准库日期。如果您使用追加,当您调用require'date'时您的文件将永远不会被加载,因为它位于数组的末尾并且标准日期会在之前找到。因此,如果