【问题标题】:size() complexity of STL containers in G++: which containers are O(n)?G++ 中 STL 容器的 size() 复杂度:哪些容器是 O(n)?
【发布时间】:2012-01-18 03:30:20
【问题描述】:

我想大多数人都明白size() 函数的复杂性并不能保证是恒定的。尽管在某些实现中,它是恒定的。

G++ 编译器可能是最常用的编译器。那么,在 G++ 的实现中,size() 的复杂度是多少?如果它因不同的容器而异,那么哪些容器具有线性复杂度?对于最常用的(如list、vector、deque、set、&map),都是常量吗?

【问题讨论】:

  • 其实这取决于你的标准库实现,而不是编译器。
  • @Jon 那么,问这个问题的最佳方式是什么?我认为编译器实现了标准库?我如何找出谁实施了它以及它是如何实施的?
  • 这是一个很好的问题,这就是为什么我只是查看标准以了解它的内容。事实证明,它完全指定了实现应该具有的复杂性——请参见下面的答案。
  • 应该只是一个强烈的建议。一些必需的东西甚至没有被削减:)
  • @LokiAstari 肯定有类似的问题,但不同的是,询问标准的具体实现超出了它的保证。对于 GNU 的 STL 中的 std::list,这很重要。

标签: c++ stl g++ complexity-theory


【解决方案1】:

对于 C++11,标准 (23.2.1) 指定 size 对于标准库的一致实现中的 所有 容器来说是 O(1)(不幸的是,这并不意味着所有实现都是一致的;例如gcc has this issue)。

对于 C++03,标准 (23.1) 规定 size “应该具有恒定的复杂性”,事实证明(感谢评论者)这是一个强大但非有约束力的建议;这意味着您必须阅读每个编译器提供的实现文档。

【讨论】:

  • “应该”表示这是一个不具约束力的要求。如果不满足要求,则不是一致性问题。
  • @JamesMcNellis:所以一个符合 C++03 标准的 O(n) 实现实际上在 C++11 中是不符合标准的(他们不拐弯抹角)?
  • 正确,这里甚至有一个 gcc 的错误报告:gcc.gnu.org/bugzilla/show_bug.cgi?id=49561
  • 谢谢大家。相应地编辑了答案。
  • AFAIK,存储大小意味着 O(1) .size() 和 O(n) .splice(),而计算它意味着 O(1) .splice() 和 O(n) .size()。如果它说.size() 应该 具有恒定的复杂性并且.splice() 可以 是线性的,那么它就是。也许标准委员会认为.size() 在不同的实现上具有不同的复杂性毕竟是一个坏主意,现在对.splice() 施加了线性复杂性。知道 C++11 中的 .splice() 怎么说吗?
【解决方案2】:

它可能会根据标准库的版本而改变。

对于 GCC 最新版本(至少到 4.6.2)List 和基于List 的版本不是恒定时间,而是实现为{ return std::distance(begin(), end()); }

MSVC 标准库会在大小发生变化时跟踪大小并仅返回其值(这使得splice() O(n),因为它必须在拼接时进行计数)。

来自我的/usr/include/c++/4.6.2/bits/stl_list.h

/**  Returns the number of elements in the %list.  */
      size_type
      size() const
      { return std::distance(begin(), end()); }

vectorsetdequemap 是常数时间。 ,

这是std::deque

  size_type
  size() const
  { return this->_M_impl._M_finish - this->_M_impl._M_start; }

queuestack实际上是容器适配器,依赖于底层容器,可以指定。但是默认是deque,它是常量。

【讨论】:

  • 最近“最高 4.1”(released on February 28, 2006) 怎么样?
  • 我不确定我是否使用了不同的版本,但也可能存在差异,例如 linux 上的 O(1) 和 mac os 上的 O(n)。至少几个月前我遇到过这个问题。
  • 抱歉是指 4.6.1,但只是检查了 4.6.2,它仍然是 O(n)。感谢您指出这一点。
  • @JoeMcGrath 感谢您的回复。那你知道vector::size(), set::size(), map::size(), deque::size()的复杂度吗?非常感谢!
  • @CodeNoob 已更新以添加答案。
【解决方案3】:

对于 G++ 5.4.0,文件 /usr/include/c++/5.4.0/bits/stl_list.h

  /**  Returns the number of elements in the %list.  */
  size_type
  size() const _GLIBCXX_NOEXCEPT
  { return this->_M_node_count(); }

对于 G++ 4.8.5,文件 /usr/include/c++/4.8.5/bits/stl_list.h

  /**  Returns the number of elements in the %list.  */
  size_type
  size() const _GLIBCXX_NOEXCEPT
  { return std::distance(begin(), end()); }

所以它对于 4.8.5 是线性的,对于 5.4.0 是恒定的

【讨论】:

    猜你喜欢
    • 2012-06-29
    • 2021-04-24
    • 2010-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-20
    • 2021-05-13
    • 1970-01-01
    相关资源
    最近更新 更多