【问题标题】:Universal hashing performs worse than modulo hashing, what is wrong?通用散列的性能比模散列差,有什么问题?
【发布时间】:2017-05-08 23:54:46
【问题描述】:

如果您不熟悉universal hashing,这主要是为了保证较少的冲突(相反,例如使用普通的旧模数),使用一些涉及随机性的相当简单的数学。问题是它对我不起作用:

size_t hash_modulo(const int value) {
    return (size_t) (value % TABLE_SIZE);
}

// prime 491 is used because its > 128, which is the size of the hash table
size_t hash_universal(const int value) {
    const size_t a = (size_t) (rand() % 491 + 1);
    const size_t b = (size_t) (rand() % 491);
    //printf("a: %zu, b:%zu\n", a, b);
    return ((a * value + b) % 491) % TABLE_SIZE;
}

我先测试模哈希,确定最长的链长(链长是指一个哈希桶的大小):

size_t get_max_chain_length(int input[TABLE_SIZE], size_t (*hash_function)(const int)) {
    HashTable *hash_table = hash_table_create(hash_function);
    if (!hash_table) {
        return 0;
    }

    for (size_t i = 0; i < TABLE_SIZE; ++i) {
        hash_table_add(hash_table, input[i]);
    }

    size_t maximum_chain_length = 0;
    for (int j = 0; j < TABLE_SIZE; ++j) {
        const size_t length = length_of_(hash_table->rows[j]);
        maximum_chain_length = (length > maximum_chain_length) ? length : maximum_chain_length;
    }

    //hash_table_print(hash_table);
    hash_table_destroy(hash_table);

    return maximum_chain_length;
}

我选择了一个导致一个非常大的链的输入(id est 一个使用普通模数表现不佳的输入),并将这个与通用散列相结合。通用散列使用随机性,因此我可以采用恒定输入并仍然得到不同的结果。

问题来了。我尝试了 100 个大小为 128 的随机输入数组,并计算平均最长链和总最长链,但两种算法的性能相似。

您可以在我的repo 中查看我的主要内容。

我的问题是:这个结果是可以预期的吗?对于使用模数已经表现不佳的输入,通用散列是否表现得更好?还是我只是搞砸了我的实施(更有可能)。

提前非常感谢!

【问题讨论】:

  • 等等,您要为每个哈希访问重新计算ab?这有什么意义?
  • 在这次尝试中 ab 应该是 static 吗?
  • @melpomene:如果它们是静态的,那么函数总是会将相同的输入散列到同一个桶中?
  • @WhozCraig 见上文
  • 因为您的方法无法实际实现可用的哈希表。

标签: c hash hashtable modulo universal-hashing


【解决方案1】:

好吧,为什么你认为模数不好?如果输入是随机的并且足够大,则模应该产生均匀分布的结果。统一散列(如您的链接所述)提供对非随机(即恶意)输入的保护,但此处并非如此。

【讨论】:

  • 这就是为什么我从模数中选择最差的分布,以检查使用通用散列是否会更好。这种方法有缺陷吗?
  • 最糟糕的分布是什么?如果输入足够大,任何随机输入都应该收敛到均匀。
  • 嗯,也许只运行一次代码。我生成随机输入并选择一个使用模数导致大桶的输入。然后我使用与 Universal 完全相同的输入来检查结果是否有所改善。而且按照规范,最大链长至少应该减少一点。
【解决方案2】:

如果您不熟悉通用散列,主要是为了保证少量的冲突……

“试图保证”并不是保证。

…(相反,使用普通的旧模数)…

链接的文章说,更简单的哈希函数 [使用模] 大约是通用的。

我生成随机输入并选择一个使用模数导致大桶的输入。然后我使用与 Universal 完全相同的输入来检查结果是否有所改善。而且按照规范,最大链长至少应该减少一点。

100 个大小为 128 的随机输入数组并不是特别大的输入。我从你的回购中运行了八次程序;在其中五次运行中,您的通用哈希将“平均最大链长度”减少了约 10%;在三次运行中,您的通用哈希将“平均最大链长度”增加了相似的数量。我注意到使用通用散列的最大链长度在每次运行中都是恒定的。

总而言之,不能保证一种哈希方法总是比另一种更好,而且您的通用哈希似乎通过经常更好而不是更好来保持其性能承诺。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-23
    • 1970-01-01
    • 2012-10-24
    • 1970-01-01
    • 1970-01-01
    • 2012-01-30
    • 1970-01-01
    • 2021-05-10
    相关资源
    最近更新 更多