Testing 如何测试我的哈希函数在最大负载方面是否良好?

Testing 如何测试我的哈希函数在最大负载方面是否良好?,testing,hash,hashtable,Testing,Hash,Hashtable,我已经阅读了关于“球和箱子”问题的各种论文,似乎如果哈希函数工作正常(即,它实际上是一个随机分布),那么如果我将n值哈希到一个具有n插槽(或箱子)的哈希表中,则以下应该/必须为真: 对于大型n而言,垃圾箱为空的概率为1/e 预期的空箱子数量为n/e 一个箱子有k个球的概率是,这是一篇引人入胜的论文/讲座——让我希望我上过一些正式的算法课 根据我刚刚读到的内容,我将尝试一下这里的一些答案,并随时投票否决我。不过,我希望你能给我一个更正,而不仅仅是投反对票:)我也会在这里交替使用n和n,这在某些圈子

我已经阅读了关于“球和箱子”问题的各种论文,似乎如果哈希函数工作正常(即,它实际上是一个随机分布),那么如果我将
n
值哈希到一个具有
n
插槽(或箱子)的哈希表中,则以下应该/必须为真:

  • 对于大型
    n
    而言,垃圾箱为空的概率为
    1/e
  • 预期的空箱子数量为
    n/e

  • 一个箱子有
    k
    个球的概率是
    ,这是一篇引人入胜的论文/讲座——让我希望我上过一些正式的算法课

    根据我刚刚读到的内容,我将尝试一下这里的一些答案,并随时投票否决我。不过,我希望你能给我一个更正,而不仅仅是投反对票:)我也会在这里交替使用n和n,这在某些圈子里是一个很大的禁忌,但由于我只是复制粘贴你的公式,我希望你能原谅我

    首先,日志的基础。这些数字以大O表示法给出,而不是绝对公式。这意味着你在寻找“在ln(n)/ln(ln(n))的顺序上”的东西,不是期望得到一个绝对的答案,而是随着n变大,n与最大碰撞次数的关系应该遵循这个公式。您可以绘制的实际曲线的细节将因实现而异(我对实际实现了解不够,无法告诉您什么是“好”曲线,但它应该遵循大O关系)。您发布的这两个公式实际上在big-O表示法中是等价的。第二个公式中的3只是一个常量,与特定的实现有关。效率较低的实现将具有更大的常数

    考虑到这一点,我会进行经验测试,因为我本质上是一名生物学家,我接受的训练是避免将硬性证据作为世界实际运行方式的指示。从N开始算起,比如说100,然后找到碰撞次数最多的箱子。这是你那次跑步的最大负荷。现在,您的示例应该尽可能接近您期望实际用户使用的内容,因此您可能希望从字典或类似的输入中随机抽取单词

    多次运行该测试,至少30或40次。因为您使用的是随机数,所以您需要确保您得到的平均最大负载接近算法的理论“预期”。期望值只是平均值,但你仍然需要找到它,你的标准偏差/标准偏差越接近平均值,你就越能说你的经验平均值符合理论期望值。一次跑步是不够的,因为第二次跑步(很可能)会给出不同的答案

    然后,增加N,也就是说,1000,10000,等等,对数增加,因为你的公式是对数的。随着N的增加,最大负载应按ln(N)/ln(ln(N))的顺序增加。如果它以3*ln(n)/ln(ln(n))的速率增加,这意味着你遵循了他们在那堂课中提出的理论

    这种实证测试也会告诉你你的方法哪里出了问题。也许你的算法在N<1000万(或其他数字)时运行良好,但超过这个数,它开始崩溃。为什么会这样?可能您的代码中有一些限制,限制为32位,但没有意识到(即,使用“float”而不是“double”),或者其他一些实现细节。这些类型的详细信息让您知道代码在实践中可以在哪里很好地工作,然后随着实际需求的变化,您可以修改算法。也许让算法在非常大的数据集上工作会使它在非常小的数据集上非常低效,反之亦然,因此准确地指出这种权衡将帮助您进一步描述如何使算法适应特定情况。总是一种有用的技能

    EDIT:证明为什么log函数的基与big-O表示法无关:

    log N = log_10 (N) = log_b (N)/log_b (10)= (1/log_b(10)) * log_b(N)
    

    1/log_b(10)是一个常量,在大O表示法中,常量被忽略。基本更改是免费的,这就是为什么你会在论文中遇到这种变化。

    经过更多的研究和尝试,我想我可以提供一些部分答案

  • 首先,
    ln
    log
    似乎是指log base-e,如果你仔细研究这个理论背后的数学原理。但正如mmr所指出的,对于O(…)估计,这并不重要

  • max load
    可以根据您喜欢的任何概率定义。使用的典型公式是

    1-1/n**c

  • 关于这个主题的大多数论文都使用

    1-1/n
    
    举个例子可能最简单

    假设您有一个包含
    1000
    slot的哈希表,并且您想要对
    1000
    事物进行哈希。假设您还想知道
    最大负载
    ,概率为
    1-1/1000
    0.999

    max load
    是最终相同的散列值的最大数量-即冲突(假设散列函数良好)

    使用公式计算得到完全相同的
    k
    散列值的概率

    Pr[ exactly k ] = ((e/k)**k)/e
    
    然后通过累计
    0..k
    项目的概率,直到总数等于或超过
    0.999
    告诉您
    k
    最大负载

    例如

    因此,在这种情况下,
    max load
    5

    因此,如果我的哈希函数在我的数据集上运行良好,那么我应该期望相同哈希值(或冲突)的最大数量为
    5

    如果不是,则可能是由于以下原因:

  • 您的数据具有小值(如短字符串),这些值散列为相同的值。单个ASCII字符的任何散列都将从128个散列值中选取1个(有很多方法可以解决这个问题
    Pr[0] = 0.37
    Pr[1] = 0.37
    Pr[2] = 0.18
    Pr[3] = 0.061
    Pr[4] = 0.015
    Pr[5] = 0.003     // here, the cumulative total is 0.999
    Pr[6] = 0.0005
    Pr[7] = 0.00007