【问题标题】:For what argument is std::vector<void*>::reserve an O(1) time operation?对于什么参数是 std::vector<void*>::reserve 一个 O(1) 时间操作?
【发布时间】:2013-01-02 23:00:58
【问题描述】:

我至少对以下问题的大致答案感兴趣:

int n;
...
std::vector<void*> vectorOfPointers;
vectorOfPointers.reserve(n);

上面提到的程序在 O(1) 中运行到哪个数字 n

让我们假设一台运行 32 位 Ubuntu 和 3 GB 内存的笔记本电脑,没有运行任何其他程序。是几万,几万,几百万?需要知道哪些信息才能评估这样一个问题?有没有办法在不进行任何实验的情况下找出答案?

我从未研究过任何有关操作系统的知识,但在我的想象中,操作系统只需 2 个步骤即可分配内存。它确定开始块的指针和块结束的指针。情况可能会更复杂,因为系统可能必须整理才能获得足够大的内存。但是如果我们假设系统只运行这一个程序,我们如何估计需要的时间呢?除了内存碎片化,还有其他方面需要考虑吗?

编辑:

对不起,我没有把我的问题说清楚。重要的是要考虑到,在调用 reserve 之前向量是空的,因此不需要复制数据。

【问题讨论】:

    标签: c++


    【解决方案1】:

    从 C++ 的角度来看,代码需要 O(1) 时间(它与容器的 当前 大小成线性关系,在您的情况下始终为零)。

    现在,您的问题似乎是关于分配 m 字节内存的复杂性。恐怕没有具体说明。

    更多讨论请见Time complexity of memory allocation

    为了补充在另一个问题中已经说过的内容,有几层复杂性:

    • 首先,malloc() 需要维护其内部数据结构。没有具体说明这样做的复杂性,但希望malloc(m) 不会花费Θ(m) 时间。但是,复杂性很可能取决于其他因素,例如内存碎片。
    • 其次,malloc() 可能需要向操作系统请求额外的内存。在这里,期望操作系统对它分配的每个内存页面做一些事情并不是没有道理的(例如,擦除它,这样你就不会看到其他人的机密数据)。如果发生这种情况,操作确实是Θ(m)

    【讨论】:

    • 谢谢,您所指的问题正是我要找的。它似乎比我想象的要复杂。但是有一些“经验法则”的近似答案吗?
    • @MartinDrozdik:经验法则是根据实际输入分析您的代码,并查看瓶颈在哪里。内存分配极不可能成为瓶颈,从而使问题变得毫无意义。
    • 其实我根本不关心瓶颈。我正在开发一种算法,我试图通过实验来估计其复杂性。我只想知道我的测量值会在多大程度上受到内存分配等因素的影响
    • @MartinDrozdik:如果这是一个问题,您可能需要预先分配内存。
    • @MartinDrozdik:要么这样,要么只是将分配移到您正在测量的代码之外。
    【解决方案2】:

    在使用 reserve() 时,您不能依赖 O(1) 复杂度。

    复杂性

    与容器大小成线性关系

    (参见cppreference

    基本上,新内存的分配是在恒定时间内进行的,但您还需要将旧内存中的旧元素复制到新内存中(因此具有线性复杂性)。

    所以在一个空向量上,reserve 可能会有一个恒定的时间,但我不确定标准是否明确说明了它。所以它可能取决于底层实现(即使我没有看到任何不这样做的理由)。

    【讨论】:

    • 在这种情况下“容器的大小”不是一直为零,使得操作O(1)?
    • 可能,但我认为将其视为 O(1) 是错误的,即使在这种情况下 - 它仍然是 O(n)。
    【解决方案3】:

    我能想到的唯一O(1)std::vector::reserve()n &lt;= capacity(),这意味着reserve() 什么都不做。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-09-22
      • 2013-06-18
      • 1970-01-01
      • 2015-01-04
      • 1970-01-01
      • 2010-09-20
      相关资源
      最近更新 更多