【问题标题】:Why use an unordered container? (C++)为什么要使用无序容器? (C++)
【发布时间】:2013-01-25 20:17:55
【问题描述】:

我已经尝试过搜索,但没有找到任何东西。

我正在学习 STL 容器,并了解顺序容器和关联容器的优缺点,但是我不确定为什么有人会更喜欢无序容器而不是关联容器,因为它肯定不会影响元素插入、查找和删除.

这纯粹是一个性能问题,即插入/删除到关联容器需要更多处理,因为它必须经过排序? 我不太了解系统方面的事情,但在我的脑海中,我觉得一个无序的容器比自动组织的容器需要更多的“维护”。

如果有人能提供一些启示,那将不胜感激。

【问题讨论】:

  • 很明显,自动组织的那个需要更多的维护:它需要在任何时候发生变化时重新组织。另一个没有。
  • 阅读书籍或尝试自己编写代码。有了经验就会明白。
  • 你用你的术语把我弄糊涂了。您将“无序容器”与“关联容器”进行对比,但这两者并不相互排斥。 std::mapstd::unordered_mapboth 关联数组。而std::setstd::unordered_set 不是。
  • “关联容器”表示“按值查找”,与“序列容器”形成对比,“按插入位置查找”。
  • 好吧,我错了。我猜“关联容器”在 C++ 中意味着不同的东西。它包括std::set 和变体。但它也包括无序变体,因此您的术语仍然令人困惑。

标签: c++ c++11 std unordered


【解决方案1】:

纯粹抽象地考虑这样一个事实,即元素的排序是您必须付费的额外“功能”,因此如果您不需要它(例如在仅查找字典中),那么您不应该必须付钱。

从技术上讲,这意味着可以通过使用哈希表以预期的查找和插入复杂度 O(1) 而不是有序容器的 O(log n) 来实现无序容器。

不过,在切线相关的注意事项上,使用字符串作为键有一个巨大的实用优势:有序容器必须在树遍历的任何地方执行完整的字符串比较,而散列容器仅执行单个散列操作(甚至可以“优化”以仅从非常长的字符串中采样固定数量的字符),并且在实践中通常会更快。

如果订购不是必需的,那么最好的办法是尝试两种容器类型(其界面几乎相同)并比较你的中的性能使用配置文件。

【讨论】:

  • 您关于字符串比较的陈述对我来说似乎不直观。我希望std::less<std::string> 是一个 eager 比较,一旦找到第一个不匹配的字符就会返回。相反,std::hash<std::string> 可能会计算整个字符串的哈希值。因此,如果您有长字符串作为键,但字符串的前几个字符都不同(我知道这是一个人为的例子)map 可能比unordered_map 更好。另外,+1 建议实际尝试一下。
  • 在常见情况下,链接容器的成本大大超过了比较/哈希计算本身的成本。请参阅第 45 分钟左右的Bjarne's talk on C++11 style,了解有关这种影响程度的令人震惊的讨论。
  • @Praetorian 字符串比较可能会比散列进行更多次。
  • @Praetorian 再想一想。哈希计算一次,其成本基本上等于将相同字符串与相等字符串比较一次。如果 key 在 map 中,则必须在最终匹配元素处至少对 string 进行一次整体比较。因此,对于几乎所有实际应用,散列 更快。​​
  • @aspiring_programmer 不,无论散列大小如何,散列实际上都是 O(1)。在任何给定时刻,哈希中的每个项目平均被重新哈希一次,因此每个项目的平均插入成本保持在 O(1),它不会增长,第 100 万个项目有 99.9999% 的机会插入成本为 1 和 0.0001需要以百万为代价进行重新散列的几率,平均为 2,即。恒定的时间。哈希基本上是作为表索引使用的,表访问当然也是O(1)。
【解决方案2】:

当不需要对对象进行排序并且您最关心对象查找的性能时,我们使用无序容器,因为无序容器在任何地方都有最快的搜索/插入是 O(1) 而不是有序容器(关联容器耗时 O(log n)),序列容器耗时 O(n))。

【讨论】:

    【解决方案3】:

    不知道为什么有人更喜欢无序容器而不是关联容器

    这些功能不是独有的。容器可以是关联的,如果是,单独的也可以是无序的。

    如果您熟悉hash maps,那就是无序容器所利用的技术。 标准库使用术语“无序”而不是“散列”,以免在需要的只是特定性能承诺时强加特定技术。 (见评论)

    【讨论】:

    • 之所以选择unordered而不是hash是因为许多实现已经有使用hash这个词的非标准版本。
    • @JesseGood,看到std:: 部分是如何被浪费的,这真的很可惜。
    猜你喜欢
    • 2016-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-11
    • 2019-12-09
    • 2012-03-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多