字符串类擦除成员函数的C++时空复杂度

Posted

技术标签:

【中文标题】字符串类擦除成员函数的C++时空复杂度【英文标题】:C++ Time and Space Complexity of string class erase member function 【发布时间】:2019-03-22 19:42:37 【问题描述】:

我想知道是否有人知道 C++ string::erase 函数的实现及其复杂性。我知道 C++ 字符串是字符的对象。我假设它没有分配和创建一个新的字符对象,然后从旧字符串 O(n) 和 O(n) 空间中复制字符。它是否在字符 O(n) 和 O(1) 空间上移动?我看过 cplusplus.com 和 Bjarne Stroustrup 的书,但找不到答案。有人可以指点我实现它的源代码或知道答案吗?

谢谢!

【问题讨论】:

只知道它会比任何自制的实施都要好。所以从用户的角度来看,它是 O(AlwaysBetterThanYourImplementation) :) @OmidCompSCI 这听起来更像是一种信仰的表达,而不是实际的知识。许多算法都很简单,最优解决方案显而易见,在这种情况下,大多数自制实现最终将与标准库的解决方案处于同一 O() 类中。几乎可以肯定 std::string::erase() 属于该类别(可能通过 memmove() 或类似的方式在 O(N) 中实现) 您要阅读的源代码在您自己的计算机上的string 头文件或它包含的某个文件中。 无论是将元素向后移动还是分配一个新字符串,最坏的情况都是 O(n)。 感谢大家的回复。谢谢马丁向我展示了标准。通读标准,它似乎将子字符串从起始索引复制到 pos 索引(跳过 xlen 字符),然后将结束字符 pos + xlen 复制到 size()。这意味着它将是 O(n) 和 O(n) 空间,除非我弄错了。 【参考方案1】:

作为stated in the comments,该标准没有为许多basic_string 函数(包括erase)指定任何复杂性要求。这部分是因为历史上存在许多不同的实现策略(最著名的是写时复制在 C++98 时代很流行),因此委员会不愿过于精确地指定任何内容。

典型的现代实现的基本行为非常类似于vector<char>:插入和删除在最后很便宜(通过摊销重新分配),在开始时很昂贵。处理小字符串时根本不分配内存(通过重用指针的空间来存储字符)。这意味着如果它变得非常短,擦除可能会导致复制整个字符串(但副本很便宜)。这也意味着迭代器和引用比vector 更容易失效

没有任何算法string 上表现得更好,但是有一些替代的数据结构具有不同的性能特征。 rope 是其中的典型代表,因为它提供的访问速度稍慢,但插入和删除速度更快。

【讨论】:

太棒了!感谢您的分解和帮助!我会投票,但我还没有足够的声誉。

以上是关于字符串类擦除成员函数的C++时空复杂度的主要内容,如果未能解决你的问题,请参考以下文章

C ++根据成员函数从向量中擦除对象[重复]

类型擦除成员函数指针的“正确”方法是啥?

在 C++ 类中使用复杂函数初始化 const 成员

C ++擦除向量末尾的一部分而不重新分配

字符串和成员函数指针的 C++ 映射

C++进阶:继承C++为什么要引入继承 | 继承概念及定义 | 基类和派生类对象赋值转换 | 继承中的作用域 | 派生类的默认成员函数 | 继承与友元/静态成员 | 复杂的菱形继承及菱形虚拟继承