【问题标题】:Vector vs Deque operator[]向量与双端运算符 []
【发布时间】:2013-09-19 15:42:23
【问题描述】:

如果我们不断地在容器的前后添加,则需要选择双端队列而不是向量。但是抵消呢? vector's 和 deque's operator[] 是否工作相同?如果不是,哪个更快?

【问题讨论】:

标签: c++ vector deque


【解决方案1】:

std::vector<T>T 元素的平面数组。 std::deque<T> 是一个大小相等的 T 数组。在这两种情况下,索引访问的复杂性都是 O(1),但std::deque<T> 需要做更多的工作来确定要访问的元素,并且还有一个指示。就像,std::deque<T> 上的迭代器需要进行多次检查(尽管算法可以优化这一点,主要是通过识别分段结构使开销相当小。因此,如果您需要经常使用下标运算符,std::deque<T> 可能是一个糟糕的选择并且在前面插入/删除时在std::vector<T> 中移动元素的成本可能会被抵消。

简单解释一下,std::deque<T>在使用下标运算符的情况下大概需要做什么:可以考虑做这些操作:

T& deque<T>::operator[](size_t n) {
    n += this->first_element;
    size_t subarray = n / size_of_subarrays;
    size_t index    = n % size_of_subarrays;
    return this->subarrays[subarray][index];
}

除法/模数运算符不太可能太昂贵,因为几乎可以肯定选择size_of_subarray 是 2 的幂,即它们基本上相当于位运算。

【讨论】:

  • 如果我循环遍历容器的连续元素,关于如何使用双端队列提高循环速度的任何建议?使用迭代器会提高速度而不是抵消吗?如果是这样,你能帮我举个例子,说明如何在双端队列上实现迭代器,还是和向量中的一样?
  • @user2653125:改进对双端队列的迭代的正确方法是利用其分段结构:而不是对双端队列进行迭代,而是分别对其每个子数组进行迭代。遗憾的是,deque 并没有公开这种分段结构,C++ 也没有定义分段迭代器的概念。迭代双端队列的主要问题是递增迭代器需要检查迭代器是否已到达段的末尾。无论是不太可能的分支还是计算成本较低,很难预测,您需要衡量。
  • 谢谢。如果由于我的算法,我只是想在前面添加并在一个方向上完全迭代容器,那么如果我创建自己的链表版本而不是向量或双端队列会更好吗?这会显着改变我的算法的性能吗?或者有没有其他更好的容器可以达到这个目的?
  • @user2653125:我希望迭代 std::deque&lt;T&gt; 比迭代 std::list&lt;T&gt; 更快,但这需要测量。天真地迭代双端队列将比迭代向量慢。理想的数据结构将是一个暴露其内部分段结构的双端队列,例如,通过使用分段迭代器,并在迭代双端队列的算法中考虑这种分段:它在迭代期间将具有几乎有效的访问,并且在插入时具有良好的行为前端和末端。我会用 deque 看看是不是太慢了。
【解决方案2】:

对于双端队列

下标接近向量的效率

Bjarne Stroustrup《C++ 编程语言》17.2.3

这并不完全相同,因为访问元素需要一个额外的间接。在许多情况下,这又会由于缓存未命中而导致额外的内存命中。因此,随机访问的速度可能要慢几个数量级(实际上,大约是 1000 倍)。但是,这会为多次连续访问摊销,因此在实践中通常不会那么糟糕。

【讨论】:

  • ... 在许多情况下,由于缓存未命中,这反过来会导致额外的内存命中。因此,随机访问的速度可能要慢几个数量级(实际上,大约是 1000 倍)。但是,这会为许多连续访问摊销,因此在实践中通常不会那么糟糕。
  • 是的——访问主内存而不是 L1 缓存大约慢了 1000 倍。这就是为什么我们首先要有缓存。但就像我说的,一旦你访问了 deque 的一部分,它通常会被完全加载到缓存中,所以如果你随后访问附近的元素,缓存命中的可能性很高,因此访问速度会更快。
  • 非常感谢,这类信息才是我们真正需要了解的,什么时候,怎么用。这在某种程度上是显而易见的,但在许多情况下,将不同方面联系在一起并不是那么简单
【解决方案3】:

std::deque 类似于std::vectors 的列表,所以如果你真的需要[] 运算符,std::vector 会更快地获取数据,但差异不大,所以你最好看看你多久前后推送数据以确定您是否需要std::vectorstd::deque

还有一点,如果你使用 for 循环来获取容器的一些索引,你最好使用iterator,因为从std::vectorstd::deque 获取数据的速度差异不会很明显。

【讨论】:

  • 它是一个向量的vector,而不是一个向量列表。至关重要的区别。
  • @KonradRudolph 无法治愈实施。但如果是vector,那么vectordeque 之间的区别就更不明显了。
猜你喜欢
  • 1970-01-01
  • 2020-03-09
  • 2015-05-01
  • 2017-10-04
  • 2011-04-14
  • 2015-07-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多