【问题标题】:C++: Why is unordered_set::find faster than find?C++:为什么 unordered_set::find 比 find 快?
【发布时间】:2020-10-03 22:19:51
【问题描述】:

当我执行 unordered_set::find 时

unordered_set<int> uniqueNum;

//code...
if(uniqueNum.find(num + k) != uniqueNum.end()) 
//code ...

这段代码的运行时间

unordered_set<int> uniqueNum;
        
//code...
if(find(uniqueNum.begin(), uniqueNum.end(), num + k) != uniqueNum.end()) 
//code...         

根据参考,unordered_set::find 是 "Worst case: linear in container size" 而 find 是“在第一个和最后一个之间的距离上达到线性:比较元素直到找到匹配”

它们不是相同的运行时吗?为什么我运行代码时 unordered_set::find 更快? std::find 是否在做我错过的幕后工作?

【问题讨论】:

  • 如果它不比线性搜索快,那它有什么用呢?
  • @SamVarshavchik 抱歉澄清一下,我知道运行我自己的代码会更快,但我不明白为什么。据我了解,它们都是 O(N) 运行时,但 unordered_set::find 完成速度更快。
  • unordered_set 是一个哈希集,因此它的查找在最坏的情况下是线性的,但平均时间是恒定的。我猜 std::find for unordered_set 迭代器将遍历所有元素,这就是为什么它总是线性的。

标签: c++ set runtime unordered-set


【解决方案1】:

这是由于它们的实施方式。 std::find 按您的预期运行。从头开始并比较每个元素,直到它到达末尾。这是相当普遍的,但不会从使用的特定数据结构中受益。但是,unordered_set 是一个哈希集,因此如果没有哈希冲突,则每个元素的查找时间都相同。

之所以说存在“容器大小线性的最坏情况”是因为如果哈希表的长度为 1,则每个条目都将放置在表中的相同位置(伪代码:@987654323 @)。如果发生这种情况,那么根据实现的不同,它最终可能看起来更像是内存中的一个列表,并且它必须按顺序检查每个项目。但在实践中,这可能永远不会发生。

【讨论】:

    【解决方案2】:

    一个无序的集合就像一个文件柜。假设您拥有一家公司所有员工的档案。文件柜有 26 个抽屉,每个抽屉都标有一个字母。每个员工的记录按姓氏的第一个字母存储。抽屉中的文件没有进一步组织。

    unordered_set::find 被告知要查找员工的记录时,它会直接进入标有姓氏首字母的抽屉并搜索该抽屉中的所有记录。当std::find 被赋予相同的任务时,它从左上角的抽屉开始检查那里的所有记录,然后移动到它旁边的抽屉,依此类推,直到检查所有抽屉或找到记录。 (请注意,左上角的抽屉不一定是“A”。)

    假设公司有 20 名员工。给定一个典型的名称分布,unordered_set::find 很可能会进入一个只有一条记录的抽屉,这就是您要查找的记录。也许它找到了两条记录。仍然快速简单。如果您的哈希函数能够胜任任务,这代表了常见情况。同时,std::find 可能需要查看所有记录才能找到您要查找的记录。有时它会很幸运并立即找到它。平均而言,它会查看一半的记录。

    但是,典型情况并不是最坏的情况。最糟糕的情况是,公司最后一次招聘活动是在一次家庭聚会上,因此所有 20 名员工都被命名为“琼斯”。通常快速的unordered_set::find 将直奔抽屉“J”,只找到该抽屉中的每个员工记录。平均而言,它会在找到所需的记录之前浏览一半的记录,与std::find 相同。

    您应该关注典型时间还是最坏情况时间?这取决于你的具体情况。有时,陷入最坏的情况是有系统的原因的,类似于在家庭聚会上招聘。另一方面,如果名字是随机分布的,在这个例子中,在同一个抽屉中有 10 条(或更多)记录的机会大约是 5×1012 中的 1 个;真正的最坏情况甚至更罕见(涉及 1026).... 通常您可以依靠快速查找。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-24
      • 2012-02-14
      • 2012-05-12
      • 1970-01-01
      • 2017-03-19
      • 1970-01-01
      • 2010-10-13
      • 1970-01-01
      相关资源
      最近更新 更多