【问题标题】:Converting integer identifiers to pointers将整数标识符转换为指针
【发布时间】:2010-11-23 06:19:45
【问题描述】:

我有 unsigned int 类型的 ID 值。我需要将 Id 映射到 恒定时间 中的指针。


密钥分配:

ID 的值在 0 到 uint_max 的范围内。大多数键将聚集到一个组中,但会有异常值。


实施:

  • 我曾考虑过使用 C++ ext hash_map 的东西,但我听说当键的潜在范围很大时,它们的性能并不太好。

  • 我还考虑过使用某种形式的链式查找(相当于递归地将范围细分为 C 卡盘)。如果某个范围内没有键,则该范围将指向 NULL。

    N = 键范围

    0级(分为C = 16,所以16个)= [0, N/16), [N/16, 2*(N/16)), ...

    1级(分为C=16,所以16*16块)=...


还有其他人对如何更有效地实施这种映射有想法吗?

更新:

我所说的常量是指每个键查找不会受到项目中值的 # 的显着影响。我并不是说它必须是一个单一的操作。

【问题讨论】:

  • 另外,请尽量减少内存使用(类似于上面的链式查找...)。请不要建议分配大小为 KEY_RANGE 的数组;)

标签: c++ algorithm data-structures hash hashtable


【解决方案1】:

使用哈希映射 (unordered_map)。这给出了~O(1) 的查找时间。您“听说”它很糟糕,但您是否尝试过、测试过并确定它是一个问题?如果没有,请使用哈希映射。

在您的代码接近完成后,对其进行分析并确定查找时间是否是程序运行缓慢的主要原因。很有可能,不会。

【讨论】:

    【解决方案2】:

    你不会得到恒定的时间。

    我可能会使用B+Tree

    【讨论】:

    • 哈希映射在大多数情况下都是常数时间。
    • 在密钥的统计随机分布上仍然摊销 O(1)。
    • 我仍然觉得说“摊销 O(1)”是隐藏真实性能的好方法。对于 N 个对象,它可能与 O(N^2) 一样糟糕(尽管可能性很小),但是嘿,它是 O(1) 摊销的!这也假设了恒定时间对象散列方法,这可能并不总是正确的。
    【解决方案3】:

    如果您的整数值是 32 位宽,那么您可以使用 64 位平台,分配 32 GB 内存(每 40 亿个指针 8 个字节),并使用平面数组。这将与您获得恒定查找时间一样接近。

    【讨论】:

    • 旁注:对于我们这些在 64 KB 是一个完整的时代长大的人来说,这甚至是可能的事实令人难以置信-出机。
    • 恒定时间意味着无论您获得相同时间的数值如何,此评论描述的是线性时间。
    • “完美哈希”的全新含义:)
    • @Tom:“线性时间”是查找时间直接取决于容器中项目数的情况。我的建议根本不做搜索,而是一个单一的索引:a[id] 其中id 是要查找的标识符,a 是大数组。
    • @Konrad:我想知道是否有人会接受这个! OP 确实说过“大多数键将聚集到一个组中”... :)
    【解决方案4】:

    为此保留 4GB 的 RAM,然后简单地将 uint 转换为指针。这绝对是恒定的时间。

    【讨论】:

      【解决方案5】:

      如果您想要一个基于树的解决方案并且您的 id 在 {0..n-1} 范围内,那么您可以使用一个非常酷的数据结构 van Emde Boas tree。这将产生 O(log log n) 中的所有操作并使用 O(n) 空间。

      【讨论】:

      • 根据我的经验,实施起来非常痛苦 :) 但是确实令人印象深刻。
      【解决方案6】:

      正如 GMan 建议的那样,unordered_map 可能是一个很好的解决方案。如果您担心此哈希映射中存在大量冲突,请使用哈希函数来消除数据的聚类。例如,您可以交换字节。

      需要注意的一点是,与已经拥有良好谱系的数据结构相比,您可能会花费更多时间调试和证明自定义数据结构。

      【讨论】:

        【解决方案7】:

        这样的地图中有多少项目,多久更改一次?

        如果所有值都适合处理器的缓存,那么带有预排序值和二进制搜索的std::vector<std::pair<unsigned int,T*>> 可能是最快的,尽管访问时间为 O(N)。

        【讨论】:

        • 大约 200k 项将在查找中。
        • 如果使用 32 位 int 和 32 位指针,则为 1.6MB。我没有这方面的经验,但在我去实现类似 vEB 树的东西之前,我会选择一些哈希很好的整数,并尝试找出带有二进制搜索的排序 std::vector 与 @987654324 的比较@ 性能方面。
        猜你喜欢
        • 1970-01-01
        • 2021-02-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-16
        相关资源
        最近更新 更多