【问题标题】:Which STL Container?哪个 STL 容器?
【发布时间】:2010-12-06 22:06:28
【问题描述】:

我需要一个容器(不一定是 STL 容器),它可以让我轻松地执行以下操作:

  • 在任意位置插入和移除元素
  • 按索引访问元素
  • 以任意顺序迭代元素

我使用了 std::list,但它不允许我在任何位置插入(确实如此,但为此我必须遍历所有元素,然后在该位置插入我想要,这很慢,因为列表可能很大)。那么您能推荐任何有效的解决方案吗?

【问题讨论】:

标签: c++ list stl containers


【解决方案1】:

我并不完全清楚您所说的“以任何顺序迭代元素”是什么意思 - 这是否意味着您不关心顺序,只要您可以迭代,或者您希望能够使用任意定义的标准进行迭代?这些是非常不同的条件!

假设您的意思是迭代顺序无关紧要,我会想到几个可能的容器:

std::map [典型的红黑树]

  • 插入、移除和访问都是 O(log(n))
  • 迭代按索引排序

hash_mapstd::tr1::unordered_map [哈希表]

  • 插入、移除和访问都是(大约)O(1)
  • 迭代是“随机的”

【讨论】:

  • 我的意思是只要我能从头/尾得到一个迭代器,然后使用该迭代器迭代所有元素
  • +1 非常巧妙的答案。 :-) 我要说它不提供索引访问,但如果你使用索引作为键,那实际上可以工作并且是体面的。
  • ...尽管索引在删除后不会是连续的,而不是在末尾。
【解决方案2】:

This diagram 会帮到你很多,我想是的。

【讨论】:

  • 这个链接是有效的,只是从另一个ip查的。
  • @sean riley: en.wikipedia.org/wiki/… -> 这是一个临时错误。
  • 那个网站没有图表!
【解决方案3】:

vectordeque 都适合。 vector 将提供更快的访问,但deque 将提供更快的插入和删除。

【讨论】:

  • 仅在结尾(和开头?)。否则,它们是一样的,不是吗?
  • vector 将所有内容存储在一个块中,因此访问速度非常快,但随机插入和删除速度很慢。 deque 存储为多个连接块,因此访问速度比 vector 慢,但随机插入和删除比 vector 快。对于双端队列来说,开始和结束处的插入更快 - 更少的缓冲区重新分配和相应的元素移动。
  • @sharptooth:在中间到末尾的双端队列插入比向量快一点。它只是在开始时快得多。
【解决方案4】:

不幸的是,您不可能在恒定时间内拥有所有这些。决定是否要进行更多的插入或读取,并以此为基础做出决定。

例如,vector 将允许您在恒定时间内按索引访问任何元素,以线性时间迭代元素(所有容器都应该允许这样做),但插入和删除需要线性时间(比列表慢) .

【讨论】:

    【解决方案5】:

    你可以试试std::deque,但它不会提供中间元素的恒定时间删除,但它支持

    • 随机访问元素
    • 恒定时间插入和移除 末尾的元素 顺序
    • 线性时间插入和删除 中间的元素。

    【讨论】:

      【解决方案6】:

      一个向量。当您擦除任何项目时,将最后一个项目复制到要擦除的项目上(或交换它们,以更快者为准)和 pop_back。要在某个位置插入(但如果顺序无关紧要!为什么要这样做!?),push_back 该位置的项目并用要插入的项目覆盖(或交换)。

      【讨论】:

        【解决方案7】:

        “以任何顺序迭代元素”是指您需要通过索引支持向前和向后,还是说顺序无关紧要?

        您想要一棵特殊的树,称为未排序的计数树。这允许 O(log(n)) 索引插入、O(log(n)) 索引删除和 O(log(n)) 索引查找。它还允许在正向或反向方向上进行 O(n) 迭代。使用这些的一个示例是文本编辑器,其中编辑器中的每一行文本都是一个节点。

        以下是一些参考资料:

        【讨论】:

          【解决方案8】:

          订单统计树在这里可能很有用。它基本上只是一棵普通的树,除了树中的每个节点都包含其左子树中的节点数。这支持所有基本操作,不比对数复杂度差。在插入过程中,只要您在左子树中插入项目,就会增加节点的计数。在删除期间,无论何时从左子树中删除,都会减少节点的计数。要索引到节点 N,请从根开始。根在其左子树中有一个节点计数,因此您检查 N 是否小于、等于或大于根的计数。如果小于,则以相同的方式在左子树中搜索。如果它更大,则下降右子树,将根的计数添加到该节点的计数,并将其与 N 进行比较。继续直到 A)您找到正确的节点,或 B)您确定有更少超过树中的 N 个项目。

          【讨论】:

            【解决方案9】:


            (来源:adrinael.net

            但听起来您正在寻找具有以下属性的单个容器:

            • 各种容器的所有最佳优势
            • 没有随之而来的缺点

            这是不可能的。一个好处导致一个坏处。选择容器是关于妥协

            【讨论】:

              【解决方案10】:

              std::向量

              [此处填充“15 个字符”]

              【讨论】:

              • 中间有插入?
              • 你是初学者吗?您是否认为 std::vector 不支持这种插入?
              • 否 - 但我读了这个问题。他已经在抱怨仅仅在std::list<> 中迭代到正确的位置是很慢的。这需要 O(N) 指针取消引用。在 std::vector 中间插入需要复制 O(N) 个元素。这可能更贵。
              • 几乎每个人都知道vector::insert() 非常昂贵,但是您是否考虑过处理器缓存? std::list 和 std::map 导致缓存未命中和访问内存非常昂贵(例如访问 L1 缓存成本:3 个周期,但访问内存需要 140 个周期!!!);但是向量具有连续存储,因此如果向量具有良好的重新分配策略(例如 128 或 256 字节),则 std::vector::insert 优于 std::list 或 std::map。虽然我同意,如果程序员不知道跨问题的缓存线边界,向量是非常糟糕的。
              • 我也同意 hashmap 或 unordered 是一个不错的选择。我同意如果 N 变得非常非常大,向量的性能会很差。
              猜你喜欢
              • 2012-05-20
              • 1970-01-01
              • 2019-10-01
              • 2012-11-23
              • 2018-12-03
              • 2010-11-18
              • 2018-03-04
              • 2010-10-17
              • 2012-09-23
              相关资源
              最近更新 更多