我用 C++ 实现了一个基于数组的二叉堆和一个基于指针的二叉堆。我进行了一个小实验,其中对于不同的输入大小 n,我进行了 n 次插入。这些元素是 int32_t 类型的,它们中的每一个都是随机(使用梅森扭曲器)从
{1,...,std::numeric_limits<int32_t>::max()}
所以我将每个实验运行 10 次,并计算完成实验所需的平均 CPU 时间。
为了计算 cpu 时间,我使用了这些函数:
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);
和
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end);
这是运行时间
对我来说,插入 n 个元素似乎需要线性时间而不是 nlogn 时间。如果我将运行时间除以 n,我会得到下图:
两个运行时间都收敛到一个常数。所以这证实了我的假设。
但是,为什么?它不应该收敛于对数函数吗?不是每次插入都是O(logn)吗?
最佳答案
通过重复插入从随机数据构建二进制堆的预期时间确实是O(n),尽管最坏情况时间(当输入已排序)是 O(n log n)。这个有趣的结果已经为人所知有一段时间了,虽然它显然不是广为人知的,大概是因为著名的保证线性时间堆化算法的流行是由于 R.W. Floyd。
直觉上,基于随机构建的堆近似于完整二叉树的假设,人们可能期望随机元素的平均插入时间为 O(1)。插入算法包括将一个元素放在堆的末尾,然后通过与它的父元素反复交换来推进它,直到满足堆约束。
如果堆是一棵完整的二叉树,平均插入时间确实是 O(1),因为在交换链中的每个点,需要进行另一次交换的概率为 0.5。因此,在一半的情况下不需要交换;四分之一的时间需要一次交换,八分之一的时间需要两次交换;等等。因此,预期的交换次数为 0 + 0.5 + 0.25 + ... == 1。
由于堆只是一个完全二叉树的近似,上面的分析是不够的。没有重新平衡就不可能维护二叉树,这具有不小的成本。但是您可以证明堆与二叉树非常相似,因此预期的插入时间仍然是 O(1)。证明是不平凡的;在线提供的一项分析是 Ryan Hayward 和 Colin McDiarmid 的“重复插入堆构建的平均案例分析”(1991 年),可从第二作者的 online publication list. 获得。
虽然 Floyd 的 heapify 算法具有更好的最坏情况性能和更紧密的内循环,但由于缓存效应,重复插入算法实际上对于大型堆可能更快(平均而言)。例如,参见 1999 年的论文 "Performance engineering case study: heap construction "作者:Jesper Bojesen、Jyrki Katajainen 和 Maz Spork。
当使用随机数据进行此类实验时,重要的是要避免计算生成随机数的成本。对于像堆插入这样相对较快的算法,调用 PRNG 的成本与算法的成本相比很可能是显着的,结果是观察到的结果因生成随机数的线性成本而有偏差。
为避免这种影响,您应该预先生成随机数组,然后测量将其变成堆的成本。
正如人们经常观察到的那样,对于 n 的所有实际值,O(log n) 是 O(1);如果你有 c1O(1) + c2O(log n) 其中 c1 比 c2 大得多,结果看起来很像 O (1).
关于c++ - 为什么我的二进制堆插入在实践中会以这种方式运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33081082/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput
我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象