时间复杂度和插入std::list
Time complexity and insertion into std::list
在std::list上的插入被声明为常数时间,无论它是否是常数时间在集装箱的前面、中间或后面制造。
另一方面,为新插入的项获取内存由标准分配器,它使用操作符new。AFAIK运营商新不保证要有恒定的时间
当操作符new在堆中查找可用空间时,它必须确保不会覆盖以前分配的内存,因此它必须保持跟踪已经在堆上分配的。我的结论是插入必须至少与列表中已存在的元素个数成线性关系
这个推理有什么错?
我的问题是:
- 怎么可能说列表上的插入是恒定的呢时间,当获取每个新节点的内存不保证是恒定的时间?
注意:重要的是要注意"真实生活时间"和在深入研究时间复杂性时所讨论的"时间"之间的区别。当讨论时间复杂度时,重要的是不要混淆"time"和"milliseconds spent doing something"的用法。
常数时间的定义是什么?
在许多情况下,维基百科经常被认为是一个糟糕的参考,但在这种情况下(以及许多其他情况下),可用的定义是正确的,将有助于描述事物的运作方式。
关于时间复杂度的文章说了以下关于常数时间:
Wikipedia - Constant Time
如果T(n)的值被一个不依赖于输入的大小的值所限定,则该算法被称为常数时间(也写为O(1)时间)。例如,访问数组中的任何单个元素需要常量时间,因为只需执行一次操作即可定位该元素。
由于插入到std::list
的时间不依赖于列表中元素的个数,所以我们说插入是常数时间;每次插入,无论何时何地,都由相同数量的初等操作组成;与列表大小无关。
但是如果operator new
不是O(1)
呢?
老实说,这并不重要,即使new
的复杂性隐式地依赖于我们分配了多少先前的实体,我们的列表插入的复杂性将保持不变。该分配与列表的大小无关。
O(1)
, constant time表示在任何给定算法中,执行某项操作的时间与输入的大小无关。即使new
不是O(1)
,我们的插入也是O(1)
,因为它只描述自己。
在列表插入中采用的路径都包含operator new
。路径不会因为列表的大小而改变,路径的复杂度是常数时间
我们在处理什么?
##c++ at freenode
中的Hannibal_Smith
说了一些很聪明的话,我非常喜欢,所以我将它包含在这篇文章中:成本模型是一个指针机。
尽管这句话可能有点误导人,但它确实起到了解释插入是O(1)
的目的,尽管部分算法不是常数时间。
插入到std::list
是从一个只处理指针的机器的角度来描述的,从这个角度来看,我们不能说它就是O(1)
。在这个算法内部完成的分配与算法本身的复杂度无关。
这是一个非常棘手的问题,在这个线程中已经讨论了一些长度。
如果我可以试着总结一下:标准做了一些微妙的区别。如果你仔细阅读,有些操作确实被指定为"常数时间",但其中std::list
插入是而不是。它被指定为"常量"(编辑:错误,见下文),并且"通用容器要求"条款(本c++标准草案中的23.2.1)解释了
本条款中所有的复杂度要求仅以对所包含对象的操作次数来说明。
(Edit:正如philip rossamen指出的那样,我错了;std::list
插入指定为"恒定时间",但我相信一般要求条款仍然适用)。因此,因为列表插入只需要在单个对象及其相邻对象上工作,所以它是"恒定复杂度",尽管它可能不一定是"恒定时间复杂度",因为没有时间复杂度保证分配。
实际上,一个好的内存分配器在分配对象的数量上不会是线性的,尽管它也可能不是常数时间。
- 使用std::multimap迭代器创建std::list
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- 使用"std::unordereded_map"映射到"std::list"对象
- 使用std::list创建循环链表
- '[](std::list& list)<int>{return std::move(list)}(list)' 是否保证将 'list' 留空?
- 如果 KEY 是 std::list 或 std::vector 而不是值,那么 std::map 的默认行为是什么?
- 为什么这个 std::queue/指向结构的指针列表直到 List.Size() == 0 才释放内存?
- "std::list::splice(std::const_iterator pos, std::list&& other)"是否保证将"其他"留空?
- 从嵌套循环中的 std::list 中删除将返回访问冲突
- 内存未释放 std::list<std::shared_ptr<std::string>> C++
- 像 std::list<std::p air<string, string>> 这样的结构在返回时会被复制吗?
- std::list<std::shared_ptr>::擦除得到了一个SIGSEGV
- 将 std::list<std::unique_ptr> 移动到向量中会尝试引用已删除的函数
- C++ DLL 返回指向 std::list<std::wstring 的指针>
- 您将如何为 std::list<std::string> 创建一个类型映射,以在<String> List in C++ 中为 Java 在 SWIG 中创建?
- std::list<std::unique_ptr>:空初始值设定项列表与默认构造函数
- 错误 C2440:"=":无法从"std::list<std::string,std::分配器<_Ty>> *'转换为"std::string*"
- 无法理解如何将新对象添加到 std::list<std::unique_ptr<classname>>
- std::list<std::future>析构函数不阻塞
- 无法反序列化 std::list<std::string>