【问题标题】:Is std::string size() a O(1) operation?std::string size() 是 O(1) 操作吗?
【发布时间】:2010-09-20 08:09:36
【问题描述】:

std::string size() 是 O(1) 运算吗?

我使用的 STL 的实现是 VC++ 内置的

【问题讨论】:

    标签: c++ visual-c++ stl stdstring


    【解决方案1】:
    size_type __CLR_OR_THIS_CALL size() const
    
    {   // return length of sequence
    
        return (_Mysize);
    
    }
    

    所以最终可能会是这样,但你永远无法确定。

    【讨论】:

    • 我认为你被否决是因为你没有回答问题,你要求读者把这些点联系起来。而且你的答案也很神秘。
    • 我没有看到任何改写。对我来说,答案仍然很神秘。 “……最终‘可能’是这样的”?代码不是取自实际实现吗?
    【解决方案2】:

    是的,std::string::size() 是 O(1)。

    【讨论】:

      【解决方案3】:

      STL 保证容器的性能至少为 O(N),但是包括 std::string 在内的许多容器可以将其实现为 O(1) 并且将。通常它要么返回一个简单的变量,要么执行 _End - _Begin 之类的操作并返回它。

      【讨论】:

        【解决方案4】:

        请参阅标准第 23.1 节中的表 65。 “a.size()”被列为“(注 A)”,表示“那些条目......应该具有恒定的复杂性”。

        第 21.3 节说字符串符合序列 (23.1) 的要求,事实上,size() 是常数时间。

        【讨论】:

          【解决方案5】:

          如果您要问 MSVC 的 string::size() 实现是否具有恒定的复杂性,那么答案是肯定的。但是Don Wakefield 提到了 C++ 标准 23.1 中的表 65,它说size() 的复杂性应该遵循“注释 A”中所说的内容。注 A 说:

          那些标有“(注 A)”的条目 应该具有恒定的复杂性。

          但是,这并不意味着这些条目应该具有恒定的复杂性。标准使用非常具体的术语,“应该”意味着它不是强制性的。

          在标准中添加了“注释 A”,以安抚那些认为应该允许 size() 具有线性复杂性的人,因此在修改容器时不必保持大小。

          所以你不能依赖size() 具有恒定的复杂性,但老实说,我不确定是否有任何实现没有恒定的string::size()

          【讨论】:

          • 附带说明,仍然可以以标准方式以 O(1) 操作检索字符串的大小:(end() - begin())。这保证 [amortized] O(1),因为 begin()end() 都必须是 O(1)(容器要求),字符串迭代器是随机访问的(字符串要求),并且 operator- 必须是 O (1) 对于支持它的迭代器(迭代器要求)。
          • ... 并且无法从内容中计算字符串的长度,因为对可以存储的值没有限制。这意味着它必须在内容的外部进行管理,因此它独立于 N。即它必须是 O(1)O(1) 不是 所有 容器的要求这一事实并不意味着它可以是容器中的O(N),只是至少可以有一个容器是非常量的,例如std::list<>
          • @DavidRodríguez-dribeas:嗯,可以使用字符串的“编码”来避免在任何地方显式存储长度。例如。使用 0 字节作为转义字符,其含义取决于以下字节:0 表示“字符串结尾”,非零表示“那么多 0 字节”。然而,可能是其他std::string 要求禁止这样做(例如,这似乎意味着数组下标不再是 O(1))。
          • @j_random_hacker:你说的是假设语言还是 C++?用一种假设的语言,我猜你可以。在 C++ 03 标准中描述 std::basic_string<>::size() 时,它指的是容器要求(即建议的常量大小),在 11 标准中,要求是明确的:复杂性:常量时间
          • @DavidRodríguez-dribeas:你是对的!在 03 标准中,21.3/2 表示“类模板basic_string符合序列的要求,如(23.1.1)中规定的那样”,序列是一种容器(23.1.1/1),并且容器要求恒定时间 begin()end()(23.1 中的表 65)很高兴听到他们在 C++11 中明确表示。
          【解决方案6】:

          这是为 msvc++ 回答该问题的一种简单方法。

          在项目中编写一些代码:

          string happy;
          happy.size();
          

          突出显示 .size 调用,右键单击,转到定义。

          在我的安装 (vs2005sp1) 中,这会将我发送到 xstring:1635,如下所示:

          size_type __CLR_OR_THIS_CALL size() const
              {   // return length of sequence
              return (_Mysize);
              }
          

          所以看起来字符串有一个名为 _Mysize 的成员,它只是返回它。

          换句话说,这是一个 O(1) 的实现。

          【讨论】:

          • 但问题是这个_Mysize是怎么计算出来的?
          • 它是一个数据成员,所以在.size()函数中没有计算,只是简单的返回。它在设置、清除、附加到字符串等时更改。
          【解决方案7】:

          对于字符串,size() 操作必须对于所有不使用 绳索(1) 的字符串实现都是常量.标准中没有明确要求要求操作为O(1),最接近的是size()应该是常数时间的通用要求,但这为任何其他复杂性度量留出了空间。

          那么为什么必须是O(1)呢?

          这是因为无法从字符串本身的内容计算大小。在 C 中,您使用 NUL 终止符来确定字符串的结尾,而在 C++ 中,NUL 与字符串中的任何其他字符一样有效。由于无法根据内容(2)计算字符串的大小,因此必须在外部处理,与字符串的实际大小无关。

          (1) C++03 标准允许实现使用 ropes 作为字符串的实现,但事实是该标准的当前实现都没有图书馆使用它们。

          (2) 如果实现使用绳索,则操作可能取决于大小,即构建绳索的块的数量(如果块通过链表或类似方式链接)构造,或者如果它们被允许具有不同的大小。但是 ropes 在我所知道的任何标准库实现中都没有使用。

          【讨论】:

            【解决方案8】:

            size() 的复杂性应该遵循“注 A”。这意味着,它应该具有恒定的复杂性,即 O(1)。虽然,我不确定实现,但 C++ 中的迭代器确实具有指向 STL 容器的关联操作,如 begin() 和 end()。这些操作具有恒定的时间复杂度,因为它们是容器要求。这意味着begin() - end() 也具有恒定的复杂性。也就是说,size() 是 O(1) 运算。

            【讨论】:

              猜你喜欢
              • 2019-12-27
              • 2012-12-03
              • 1970-01-01
              • 2011-09-24
              • 1970-01-01
              • 2010-09-18
              • 1970-01-01
              相关资源
              最近更新 更多