【问题标题】:What is the time complexity of std::deque::erase function?std::deque::erase 函数的时间复杂度是多少?
【发布时间】:2014-11-29 23:40:41
【问题描述】:

Here 它对时间复杂度的描述如下:

与擦除(破坏)的元素数量成线性关系。另外,取决于特定的库实现,在位置和双端队列的一端之间的元素数量上最多有一个额外的线性时间。

从第一句话我明白,如果你想擦除双端队列中的任何数字,最坏情况的复杂度将是 O(1)。

现在第二句话让我感到困惑。取决于特定的库实现是什么意思?我正在使用 STL 库,即 GCC 编译器附带的同一个库。在我的案例中,如何了解此函数的正确时间复杂度?

我需要它是 O(1),因为我正在运行 O(n) 擦除调用,如果 std::deque::erase 是 O(n),我的算法将具有二次复杂度,这是我不想要的。

【问题讨论】:

  • “双端队列中的任何数字”是什么意思?!
  • “STL 库”a) 不是一个东西,b) 不是一个实现
  • 对不起,我的意思是双端队列中的任何元素,在我的例子中它只是一个整数。

标签: c++ stl


【解决方案1】:

如果你必须从你的双端队列中删除 n 项,你通常需要使用 remove/erase 成语。

您从std::remove 开始删除n 项目本身。这基本上将您的收藏分为两部分:开始时您没有删除的部分,以及末尾包含您不再关心的内容的一些空间。

它返回一个指向这两者之间边界的迭代器。然后,您可以从那里擦除到最后(一次)以摆脱您不再关心的项目。

std::remove 基本上做了我认为的“涟漪副本”——它从头到尾遍历集合,当它找到你想要删除的项目时,它会找到你想要保留的下一个项目,并将其复制到您要删除的那个1

如果您不需要维护您保留的项目的顺序,您通常可以进一步提高速度。从集合的开头开始,找到您想要删除的项目(即,您当前要删除的项目erase)。从 end 开始,找到您想要保留的项目(即,您不会 erase 的项目)。交换这两个项目,并继续“向内”搜索,直到两个位置相遇。现在,您要删除的所有项目都在集合的末尾。您可以在 O(1) 中将它们全部擦除。

理论上,这两者的总体复杂度是相同的——都是 O(N)。然而,在许多情况下,复制一个项目相对成本很高(而只是确定是否保留该项目)。这最大限度地减少了复制/移动的项目数量,因此当复制/移动成本高昂时,它可以节省相当多的时间(尽管如前所述,如果剩余对象的顺序很重要,则不适合)。


  1. 请注意,从 C++11 开始,这些可以是移动而不是副本(例如,如果您提供移动迭代器)。

【讨论】:

    【解决方案2】:

    cplusplus.com 涵盖 C++ 标准库,而不是原始 STL。 C++ 标准库包含most of STL,它有几个实现,通常(如果不总是)从 STL 代码派生,但可能会以各种方式对其进行更改。 GCC 实现实际上是对 STL + GNU 的修改。按照标准,erasedeque中的元素个数上可能是线性的。

    如果你想在你的实现中找出这个操作的复杂性,要​​么阅读the manual(虽然我在任何地方都找不到deque),阅读源代码或配置文件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-06
      • 1970-01-01
      • 2012-07-31
      • 2020-12-03
      • 2017-09-11
      相关资源
      最近更新 更多