【问题标题】:Benefit of slist over vector?slist 优于向量的好处?
【发布时间】:2009-05-25 15:08:06
【问题描述】:

我需要的只是一个动态增长的数组。我不需要随机访问,我总是插入到最后,从头到尾阅读。

slist 似乎是第一选择,因为它提供了我需要的足够多的东西。但是,我不知道使用 slist 而不是 vector 可以获得什么好处。此外,我读过的一些关于 STL 的材料说,“向量通常是访问元素以及从序列末尾添加或删除元素的最有效时间”。因此,我的问题是:就我的需求而言,slist 真的比 vector 更好吗?提前致谢。

【问题讨论】:

  • 请注意,slist 是 sgi STL 发行版的一部分,但不是 C++ 标准库的一部分。不过,在 C++0x/C++1x(下一个 C++ 版本)中有一个 std::forward_list。
  • 谢谢,我刚才也知道了。
  • STL中还有一个std::list类。

标签: c++ list stl vector


【解决方案1】:

对于初学者来说,slist 是非标准的。

根据您的选择,链表会比向量慢,相信它。造成这种情况的原因有两个:

  1. 首先是缓存局部性;矢量将其元素线性存储在 RAM 中,这有助于缓存和预取。
  2. 其次,附加到链表涉及动态分配,这会增加大量开销。相比之下,向量大部分时间不需要分配内存。

但是,std::deque 可能会更快。 In-depth performance analysis 表明,尽管有相反的偏见,std::deque 在性能(如果不需要随机访问)方面几乎总是优于 std::vector,因为它改进了(分块)内存分配策略。

【讨论】:

  • 是什么让你觉得 slist 会更慢,这个神秘的(并且适用于所有应用程序)性能评估在哪里? sgi.com/tech/stl/Deque.html 说,“deque 与向量的主要不同之处在于,deque 还支持在序列开头的恒定时间插入和删除元素。”但是 OP 明确表示他一开始就没有进行插入或删除。
  • 另外,我很难相信您找不到 slist 的文档。
  • 马修:被指控有罪:我很懒惰。关于您的指控:SGI 文章所说的内容已经过时了;这被认为是正确的,但基准测试只是表明deque 的性能优于vector,即使在矢量典型用法中也是如此。我已经链接了相关分析。
  • 确实如此。如果我们不处理很少的数据项,我也会推荐双端队列。 deque 是 std::stack 的默认底层序列并非巧合。但是,对于少数项目,vector 应该是默认值。 (std::stack 不知道会推送多少项目,所以使用双端队列是安全的方式)。
  • 顺便说一句,这是另一个很好的例子,为什么调用标准库“STL”会导致很多混乱。我从不这样做,因为“STL”的含义很多,而C++标准库的含义只有一个。
【解决方案2】:

是的,如果您总是从头到尾阅读,slist(链表)听起来是不错的选择。可能的例外是,如果您将在最后同时插入大量元素。那么,如果你适当地使用reserve,向量可能会更好。

当然,配置文件以确保它更适合您的应用程序。

【讨论】:

  • 这听起来与我写的(并用数据备份)相反,所以它可能不对。
  • 您没有提供关于 slist 的任何数据,只是提供了模糊的承诺,以及对其他两个(除了 slist)结构的比较。
  • 再次:对不起。显然我有点愚蠢,我混淆了基准。
【解决方案3】:

Matt Austern(“Generic Programming and the STL”的作者和一般 C++ 大师)强烈主张将单链表包含在即将到来的 C++ 标准中;有关更多详细信息,请参阅他在http://www.accu-usa.org/Slides/SinglyLinkedLists.ppt 的演讲和他在http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2543.htm 的长文,包括对可能指导您选择这种数据结构的权衡的讨论。 (请注意,目前提议的名称是 forward_list,尽管 slist 是 SGI 的 STL 和其他流行库中的传统名称)。

【讨论】:

    【解决方案4】:

    我会第二次(或者第三次......)认为std::vectorstd::deque 将完成这项工作。我唯一要补充的是一些额外的因素,它们应该指导std::vector<T>std::list<T> 之间的决定。这些和T的特性以及你打算用什么算法有很大关系。

    首先是内存开销。 Std::list 是基于节点的容器,因此如果 T 是原始类型或相对较小的用户定义类型,则基于节点的链接的内存开销可能是不可忽略的 - 考虑到 std::list<int> 可能对每个元素至少使用3 * sizeof(int) 存储,而std::vector 将仅使用具有较小标头开销的sizeof(int) 存储。 Std::dequestd::vector 类似,但开销很小,与 N 呈线性关系。

    下一个问题是复制构建的成本。如果T(T const&) 非常昂贵,那么请避开std::vector<T>,因为随着向量大小的增长,它会导致出现一堆副本。这就是std::deque<T> 显然是赢家而std::list<T> 也是竞争者的地方。

    通常指导容器类型决策的最后一个问题是您的算法是否可以使用 std::vectorstd::deque 的迭代器失效约束。如果您将大量操作容器元素(例如,排序、在中间插入或洗牌),那么您可能想要倾向于std::list,因为操作顺序只需要重置一些链接指针。

    【讨论】:

      【解决方案5】:

      我猜你的意思是 std::list 的“slist”。当您需要对一系列元素进行快速、随机访问、保证连续内存和快速顺序读取(IOW,从头到尾)时,向量是很好的选择。当您需要在序列的开头或结尾快速(恒定时间)插入或删除项目时,列表是很好的选择,但不关心随机访问或顺序读取的性能。

      差异的原因在于 2 的实现方式。向量在内部实现为项目数组,当添加项目时达到其大小/容量时需要重新分配。列表被实现为双向链表,这可能导致顺序读取的缓存未命中。随机访问列表还需要从列表中的第一个(或最后一个)项目开始扫描,直到找到您请求的项目。

      【讨论】:

      • 刚刚意识到,slist,一个单链表,不标准吗?它确实出现在 HP/SGI STL 中。
      • 不幸的是,std::list 是一个双向链表,考虑到 OP 的描述要求,这是完全没有必要的。否则,我同意这一点。
      【解决方案6】:

      对我来说,std::deque 听起来不错。它具有向量的内存优势,例如为每个“slab”(有利于 CPU 缓存)分配连续内存,没有像 std::list 那样的每个元素的开销,并且不需要将整个集合重新分配为 std::vector做。阅读更多关于std::deque here

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-04-06
        • 2019-02-18
        • 1970-01-01
        • 2012-07-06
        • 2019-12-29
        • 1970-01-01
        • 2011-08-20
        相关资源
        最近更新 更多