- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我用 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/
我正在尝试将谷歌地图集成到 Xamarin Android。但是,如标题中所写,收到错误。此错误出现在我的 SetContentView (Resource.Layout.Main); 上,如下所示:
在 Delphi 中如何以非文本模式打开二进制文件?类似于 C 函数 fopen(filename,"rb") 最佳答案 有几个选项。 1。使用文件流 var Stream: TFileStrea
我现在正在处理一个问题,如下所示: 有两个数字 x1 和 x2 并且 x2 > x1。 例如 x1 = 5; x2 = 10; 而且我必须在二进制表示中找到 x1 和 x2 之间的总和。 5 = 10
我有这个“程序集”文件(仅包含 directives ) // declare protected region as somewhere within the stack .equiv prot_s
有没有办法在powershell中确定指定的文件是否包含指定的字节数组(在任何位置)? 就像是: fgrep --binary-files=binary "$data" "$filepath" 当然,
我是一名工程师,而不是软件程序员,所以请原谅我的无知。 我编写了一个 Delphi(7SE) 程序,用于从连接到两个数字温度计的 USB 端口读取“真实”数据类型。 我已经完成了该计划的大部分内容。
我有一些代码,例如: u=(float *)calloc(n, sizeof(float)); for(i=1; i
typedef struct pixel_type { unsigned char r; unsigned char g; unsigned char b;
如何判断二进制数是否为负数? 目前我有下面的代码。它可以很好地转换为二进制文件。转换为十进制时,我需要知道最左边的位是否为 1 以判断它是否为负数,但我似乎无法弄清楚该怎么做。 此外,我如何才能让它返
我有一个带有适当重载的 Vect*float 运算符的 vector 类,我正在尝试创建全局/非成员 float*Vect 运算符,如下所示:(注意这是一个经过大量编辑的示例) class Vect
对于使用 C 编程的项目,我们正在尝试将图像转换为二进制数据,反之亦然。我们在网上找到的所有其他解决方案都是用 C++ 或 Java 编写的。这是我们尝试过的方法: 将图像转换为包含二进制数据的文本文
我需要对列表的元素求和,其中包含所有零或一,如果列表中有 1,则结果为 1,否则为 0。 def binary_search(l, low=0,high=-1): if not l: retu
我到处搜索以找到将 float 转换为八进制或二进制的方法。我知道 float.hex 和 float.fromhex。是否有模块可以对八进制/二进制值执行相同的工作? 例如:我有一个 float 1
当我阅读有关 list.h 文件中的 hlist 的 FreeBSD 源代码时,我对这个宏感到困惑: #define hlist_for_each_entry_safe(tp, p, n, head,
我不知道出了什么问题,也不知道为什么会出现此错误。我四处搜索,但我终究无法弄明白。 void print_arb_base(unsigned int n, unsigned int b) {
在任何语言中都可以轻松地将十进制转换为二进制,反之亦然,但我需要一个稍微复杂一点的函数。 给定一个十进制数和一个二进制位,我需要知道二进制位是开还是关(真或假)。 示例: IsBitTrue(30,1
在下面的代码中,我创建了两个文件,一个是文本格式,另一个是二进制格式。文件的图标显示相同。但是这两个文件的特征完全相同,包括大小、字符集(==二进制)和流(八位字节)。为什么没有文本文件?因为如果我明
我想通读一个二进制文件。谷歌搜索“python binary eof”引导我here . 现在,问题: 为什么容器(SO 答案中的 x)不包含单个(当前)字节而是包含一大堆字节?我做错了什么? 如果应
为什么只允许以 10 为基数使用小数点?为什么以下会引发语法错误? 0b1011101.1101 我输入的数字是否有歧义?除了 93.8125 之外,字符串似乎没有其他可能的数字 同样的问题也适用于其
boost 库中有二进制之类的东西吗?例如我想写: binary a; 我很惭愧地承认我曾尝试找到它(Google、Boost)但没有结果。他们提到了一些关于 binary_int<> 的内容,但我既
我是一名优秀的程序员,十分优秀!