【问题标题】:How does std::list.size() have constant complexity? [duplicate]std::list.size() 如何具有恒定的复杂性? [复制]
【发布时间】:2017-05-15 19:27:37
【问题描述】:

在学校我了解到链表由带有指向列表中下一个元素的指针的元素组成,而链表的缺点是查找大小具有线性复杂性,因为您必须遍历每个元素并计数.然而,我注意到在 C++11 中,std::list.size() 具有恒定的复杂性。这怎么可能?

【问题讨论】:

标签: c++ c++11 linked-list


【解决方案1】:

很可能只保留一个成员变量,每当您添加或删除元素时,它就会更新。或者,如果您将两个列表合并在一起,只需将它们的计数相加即可。

那么你不必为了计算元素而遍历整个列表。

【讨论】:

    【解决方案2】:

    这很容易。它缓存它。你可以缓存任何东西,只要你不让它变得无效。保持缓存有效有多难?1

    为什么在 C++11 中?又是什么意思?

    在 C++11 之前,std::list::size 没有提到它有多复杂。

    有些实现保留了大小字段,有些则没有。保留大小字段的优点是.size() 是恒定时间; not 的好处是可以在恒定时间内完成一些拼接操作。

    在跟踪size() 的情况下,拼接操作需要您计算正在拼接的节点数。这阻止了它成为常数时间,它变成了 O(n)。

    C++11 决定,因为所有其他 .size() 函数都是常数时间,它们将要求 list 也具有常数时间大小。这破坏了一些 std::lists 的 ABI,并阻止了恒定时间拼接。


    1 计算机编程有两个难题。命名事物、缓存失效和关闭一个错误。

    【讨论】:

    • ABI 在应用程序二进制接口中?这个概念与 C++ 类的实现有什么关系?我不明白您所说的“破坏 ABI”是什么意思。
    • @VioletGiraffe 向类中添加成员会使其变大,并且已经破坏了 ABI。
    • @VioletGiraffe 库 ABI。请参阅gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html 了解 libstdc++ 在这里谈论我所说的 ABI 的含义。基本上,破坏了与以前版本的 std::list 的二进制兼容性,因此针对 C++11 之前的 std::list 和符合 C++11 的代码编译的代码对于所有 T 都有不同的 sizeof(std::list<T>),因为额外的字段.
    • 它确实打破了这一点,但我不相信 C++ 曾经保证不同标准版本之间甚至不同库实现之间的二进制兼容性。期望应用程序使用与编译时不同的库二进制文件从来都不是合理的。
    • @JesperJuhl 在splice(pos, sourceList, begin, end) 期间遍历节点仅当我们想要更新正在操作的列表中的缓存大小值时才需要。我们只需要在size() 保证为 O(1) 的情况下这样做。
    猜你喜欢
    • 1970-01-01
    • 2013-10-09
    • 1970-01-01
    • 2019-09-10
    • 2014-12-20
    • 1970-01-01
    • 2018-12-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多