在std :: list上插入声称是恒定时间,无论是否 在容器的正面,中间或后面制作。
另一方面,新插入项目的内存获取由处理 标准分配器,它使用operator new。 AFAIK操作员new不保证 有恒定的时间。
当operator new查找堆中的可用空间时,必须确保它 不会覆盖以前分配的内存,因此必须跟踪 已经在堆上分配的内容。我总结说插入 必须至少与列表中已有的元素数量成线性关系。
这种推理有什么问题?
我的问题是:
答案 0 :(得分:3)
注意:重要的是要注意"实际生活时间"而且"时间"谈到潜入时间复杂性时谈到的。当时间复杂性成为主题时,重要的是不要将"时间" 的使用与"毫秒花费在做某事上的事情混淆起来" #34;
什么是恒定时间的定义?
在许多情况下,维基百科通常被认为是一个不好的参考,但在这种情况下(以及许多其他情况),可用的定义是正确的,将有助于描述事物的运作方式。
关于time complexity的文章说明了以下常量时间:
如果T(n)的值受不依赖于输入大小的值限制,则称算法是恒定时间(也写为O(1)时间)。例如,访问数组中的任何单个元素需要恒定的时间,因为只需要执行一个操作来定位它。
由于插入std::list
不依赖于列表中元素的数量,我们说插入是恒定时间;每次插入,无论何时何地,都包含相同数量的基本操作;没有与列表大小有关。
但如果operator new
不是O(1)
怎么办?
老实说,这并不重要,即使new
的复杂性隐含地取决于我们分配了多少先前的实体,我们的 list-insertion 的复杂性将是不变。分配对列表的大小无动于衷。
O(1)
,常量时间,意味着执行某些操作的时间与任何给定算法中的输入大小无关。即使new
不是O(1)
,我们的插入也是O(1)
,因为它只描述了自己。
list inseration 中包含的路径包括operator new
。由于列表的大小,路径不会改变,路径的复杂性是恒定时间。
那我们在处理什么?
Hannibal_Smith
中{p> ##c++ at freenode
说了一些聪明的东西,我非常喜欢它,我将把它包含在这篇文章中:成本模型是一个指针机器。
尽管句子可能有点误导,但它确实有助于解释插入是O(1)
的方式,即使算法的某些部分不是常数时间。
从作为仅处理指针的机器的角度来描述插入std::list
,从这个角度来看,不能说它只是O(1)
。在该算法中完成的分配与算法本身的复杂性无关。
答案 1 :(得分:1)
这是一个非常棘手的问题,已在this thread中详细讨论过。
如果我可以尝试总结一下:标准会做出一些微妙的区分。如果您精确地阅读它,某些操作 确实被指定为“恒定时间”,但std::list
插入不。它被指定为“常量”(编辑:错误,见下文),“一般容器要求”条款(this draft of the C++ standard中的23.2.1)解释了
本条款中的所有复杂性要求仅根据所包含对象的操作次数进行说明。
(修改:正如FilipRoséen指出的那样,我错了; std::list
插入 被指定为“常数时间”,但我相信一般要求条款仍然适用)。因此,因为列表插入只需要处理单个对象及其邻居,所以它是“常量复杂性”,即使它可能不一定是“常量时间复杂性”,因为没有时间复杂性保证分配
实际上,一个不错的内存分配器不在分配的对象数量上是线性的,尽管它可能也不是恒定的时间。