【问题标题】:Down sides of abusing O(1) lookup of a hash table?滥用 O(1) 查找哈希表的缺点?
【发布时间】:2020-11-10 02:22:40
【问题描述】:

哈希表是非常常见的数据结构,用于解决竞争性编程/面试中出现的编码问题。

哈希表采用键值对,以便您可以查找键并获取值。但是,我经常发现自己需要 O(1) 查找键,而不是真正关心值。

例如:

如果我想知道之前是否使用过某些strings,我可能会将它们插入到带有key: stringvalue: bool 的哈希表中,其中布尔值始终为真。

做这样的事情有什么不好的地方?是否有其他不需要键值对的数据结构可以提供 O(1) 查找?

【问题讨论】:

  • 哈希表有很多种,都有自己的性能特点。有你感兴趣的特定类型吗?例如,a std::unordered_map 基本上必须实现为链表数组,我相信您知道遍历列表的性能损失。
  • unordered_set<type, bool> 哈希表的泛化,具有 O(1) 查找/插入。使用它没有真正的缺点。与 C++ 中的任何集合类一样,YMMV 在实现和内存分配开销方面的性能。
  • @selbie 不知道这一点,你
  • 所有哈希表实现在最坏情况下的性能都很差。很大程度上取决于散列值的分布程度。
  • 您也可以尝试使用 O(logn) 的其他数据集,对于较小的输入,c 常量可能更小并提供更好的性能。试试看。

标签: c++ hashtable


【解决方案1】:

除非你有一个完美的哈希算法,否则你会遇到冲突。此时,您必须查看您的实际哈希表实现。每个都有其优点和缺点,目前所有std::unordered_map(和std::unordered_set?)都实现为带有链表的桶,这使得你的O(1)成为O(N)的最坏情况。 平均值仍然是 O(1),所以如果你的系统不是时间关键的并且你使用了一个好的散列,就像几年前一样,字符串的散列使用了一些学术上接受的好的算法,然后使用散列集。另一方面,如果您无法接受最坏情况的 O(N) 查找,请使用 std::mapstd::set

  • 注意 1:所有哈希表都有一个致命弱点,这使得它们在最坏的情况下为 O(N),除非您的存储桶被实现为平衡树。
  • 注意 2:完美的散列是没有冲突的。
  • 注意 3:有一些文献可以说明如何从已知数据中生成完美哈希,但尚未看到任何关于未知数据的完美哈希。
  • 注 4:如果你找到后者,那么你可能能够证明 P = NP。

【讨论】:

    【解决方案2】:

    您应该按照预期的方式使用数据结构。然后您可以分析您的代码以查看性能是否足够。如果不是,则优化瓶颈。

    话虽如此,检查字符串是否已被使用的更好的数据结构是std::unordered_setstd::set。您的用例是集合数据结构的典型用例。 Wikipedia:

    在计算机科学中,集合是一种抽象数据类型,可以存储 唯一值,没有任何特定顺序。它是一台电脑 有限集的数学概念的实现。不像 大多数其他集合类型,而不是检索特定元素 从一组中,人们通常会测试一组成员的值。

    【讨论】:

      【解决方案3】:

      如果这个容器的唯一目的是测试一个字符串是否已经被使用,那么unordered_set(唯一键的集合,按键散列)就可以了。

      无序集是一个关联容器,它包含一组 Key 类型的唯一对象。搜索、插入和删除 平均恒定时间复杂度。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-18
        • 2017-02-23
        • 2018-02-13
        • 2018-07-14
        • 1970-01-01
        • 2012-07-17
        相关资源
        最近更新 更多