【问题标题】:Efficiently insert integers into a growing array if no duplicates如果没有重复,则有效地将整数插入到不断增长的数组中
【发布时间】:2012-09-15 08:20:29
【问题描述】:

有一种数据结构,其行为就像一个不断增长的数组。当且仅当这些整数在此数据结构中没有重复时,未知数量的整数才会被一一插入。

最初我认为std::set 就足够了,它会随着新整数的进入而自动增长,并确保没有重复。

但是,随着集合变大,插入速度会下降。那么除了哈希之外还有其他的想法吗?

附言

我想知道诸如异或所有元素或构建稀疏表(就像 rmq 一样)之类的任何技巧都适用吗?

【问题讨论】:

  • 整数值是否有上限?
  • @Jon,2∧32的上限
  • 你能给出这些操作的复杂性吗?如果我们没有它们,许多数据结构都是可能的。例如,二叉树或链表。
  • @Ben 如果可能的话,所需的插入复杂度将是 o(1)。
  • 你知道整数个数的数量级吗?可能是 10 个、1000 个还是 1000000 个?

标签: c++ algorithm


【解决方案1】:

如果您愿意在问题上花费内存,2^32 位是 512MB,此时您可以只使用一个位字段,每个可能的整数一位。撇开 CPU 缓存效应不谈,这会产生 O(1) 的插入和查找时间。

如果不了解您的用例的更多信息,很难说这是否值得使用内存,还是几乎没有任何收益的巨大内存开销。

【讨论】:

  • 我想到了位图,但又怕巨额的内存开销,一无所获。感谢任何方式
  • 实际上,我认为这将尽可能快。通过插入,我认为 Jon 的意思是做类似 seen_numbers[number] = true; 的事情,假设你使用类似 vector<bool> 的东西。
【解决方案2】:

该站点包括所有可能的容器,并为每个动作布置它们的运行时间, 所以也许这会有用:

http://en.cppreference.com/w/cpp/container

似乎建议的 unordered_set 是您最好的方法。

【讨论】:

    【解决方案3】:

    你可以试试std::unordered_set,它应该被实现为一个哈希表(好吧,我不明白你为什么写“除了哈希”;std::set通常被实现为一个平衡树,这应该是原因插入性能不足)。

    【讨论】:

    • 对,set是用rb树实现的?随着树的增长,插入速度下降。哈希是可以的,但我只是想要一些新的想法。
    • 红黑树提供了相当好的、一致的性能(低可变性),但平均速度不如 Treaps。基于哈希表的集合数据类型在这里可能是最好的。
    【解决方案4】:

    如果数字在某个范围内,那么您可以创建多个std::set 作为存储桶。

    EDIT-根据您指定的范围,std::set应该足够快。 O(log n) 对于大多数目的来说已经足够快了,除非你做了一些测量并且发现它对你的情况来说很慢。

    您还可以使用Pigeonhole Principlesets 来拒绝任何可能的重复,(适用于当集合变大时)。

    【讨论】:

    • 没有范围,它们只是 32 位整数
    • @Alcott:那么,确实有一个范围:) 0 - 4294967295
    • @Alcott:这取决于您期望的输入类型。这是一个例子 - 假设有多个集合,一个桶的范围从 10000 到 25000,如果一个元素落在这个范围内,你只需要检查这个特定集合的大小,如果它 = 15000,你不需要需要执行insert(),因为这个元素是重复的。
    【解决方案5】:

    位向量可用于检测重复项

    【讨论】:

      【解决方案6】:

      要做出最佳决策,还需要更多的要求。该建议基于以下限制: 奥尔科特 32 位整数,大约有 10.000.000 个元素(即 2^32 中的任何 10m)

      这是一个 BST(二叉搜索树),其中每个节点存储两个值,即连续区域的开始和结束。第一个元素存储区域开始的数字,第二个元素存储最后一个。这种安排允许大区域,希望你用很小的树高达到 10M 的限制,所以便宜的搜索。具有 10m 个元素的数据结构将占用每个节点 8 个字节,加上每个节点最多两个子节点的链接(2x4 字节)。这样就可以为所有 10M 元素制作 80M。当然,如果通常插入更多元素,您可以跟踪一次没有插入的元素。 现在,如果您需要非常小心空间,并且在运行模拟和/或统计检查后发现有很多小区域(长度小于 32 位),您可能希望将节点类型更改为一个开始的数字区域,加上位图。

      如果您不必对齐对位图的访问,例如,您只有 8 个元素的连续块,那么您的备忘录要求是节点为 4+1,子节点为 4+4 字节。希望这会有所帮助。

      【讨论】:

        猜你喜欢
        • 2017-08-04
        • 1970-01-01
        • 2015-05-03
        • 2018-05-30
        • 1970-01-01
        • 2017-06-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多