【问题标题】:Which hash function is better fitted to represent 128bit random id in a small hash-table哪个哈希函数更适合在小哈希表中表示 128 位随机 id
【发布时间】:2019-03-27 18:40:58
【问题描述】:

在我的课堂上,我做了以下练习:

我有 128 位的 GUID(全球唯一标识符)。

hashID 为 000 到 899 的桶中哪个哈希函数更适合表示值,每个桶有 100 个空闲位置来存储哈希冲突?

我想比较以下哈希函数:

a) h(a) = a mod 900
b) h(a) = a mod 887
c) h(a) = a^2 mod 887
d) there are not enough information to answer this question

我有什么:

我认为使用 a^2 并不好,因为它只会在前几千个 id 中给我们带来好处,它们应该更好地分布,但之后,我可能不得不进行更多的碰撞探测来存储这些其他存储桶中的值。

我已尝试完成上述行为: 在下面的 sn-p 中,我生成了 90000 个“随机”唯一数字,这些数字存储在地图中,哈希函数遵循 mod 900。我知道由于某些原因,素数更适合用于哈希函数。

随机性仅实现最大 32 位。但我认为这应该不是太重要,因为我没有使用 128bit max。

m = null;
uniqueMap = new Map();
hash = (z, p) => z % p ;

function getRandomInt(max) {
  guid = Math.floor(Math.random() * Math.floor(max));
  if (uniqueMap.has(guid)) return getRandomInt(max);
  return guid;
}


map = new Map();
for (var i = 1; i <= 90000; i++) {
  h = hash(getRandomInt(2147483647), 900);
  map.has(h) ? map.set(h, map.get(h) + 1) : map.set(h, 1);
}

map.forEach((a) => m = Math.max(a, m))

console.log(m);

下一个 sn-p 具有相同的功能,但使用 mod 887:

m = null;
uniqueMap = new Map();
hash = (z, p) => z % p ;

function getRandomInt(max) {
  guid = Math.floor(Math.random() * Math.floor(max));
  if (uniqueMap.has(guid)) return getRandomInt(max);
  return guid;
}


map = new Map();
for (var i = 1; i <= 90000; i++) {
  h = hash(getRandomInt(2147483647), 887);
  map.has(h) ? map.set(h, map.get(h) + 1) : map.set(h, 1);
}

map.forEach((a) => m = Math.max(a, m))

console.log(m);

还有一个^2:

m = null;
uniqueMap = new Map();
hash = (z, p) => z % p ;

function getRandomInt(max) {
  guid = Math.floor(Math.random() * Math.floor(max));
  if (uniqueMap.has(guid)) return getRandomInt(max);
  return guid;
}


map = new Map();
for (var i = 1; i <= 90000; i++) {
  h = hash(Math.pow(getRandomInt(2147483647),2), 887);
  map.has(h) ? map.set(h, map.get(h) + 1) : map.set(h, 1);
}

map.forEach((a) => m = Math.max(a, m))

console.log(m);

合一:

m = null;
uniqueMap = new Map();
hash = (z, p) => z % p ;

function getRandomInt(max) {
  guid = Math.floor(Math.random() * Math.floor(max));
  if (uniqueMap.has(guid)) return getRandomInt(max);
  return guid;
}


map = new Map();
for (var i = 1; i <= 90000; i++) {
  h = hash(getRandomInt(2147483647), 900);
  map.has(h) ? map.set(h, map.get(h) + 1) : map.set(h, 1);
}

map.forEach((a) => m = Math.max(a, m))

console.log(m);

m = null;
uniqueMap = new Map();
map = new Map();
for (var i = 1; i <= 90000; i++) {
  h = hash(getRandomInt(2147483647), 887);
  map.has(h) ? map.set(h, map.get(h) + 1) : map.set(h, 1);
}

map.forEach((a) => m = Math.max(a, m))

console.log(m);

m = null;
uniqueMap = new Map();
map = new Map();
for (var i = 1; i <= 90000; i++) {
  h = hash(Math.pow(getRandomInt(2147483647),2), 887);
  map.has(h) ? map.set(h, map.get(h) + 1) : map.set(h, 1);
}

map.forEach((a) => m = Math.max(a, m))

console.log(m);

如果我比较这 3 种方法,它们会告诉我,在不为 guid 供电的情况下,使用 mod a^2 的最高碰撞计数高于 887 和 900。 所以我认为这不是正确的答案。

但是我应该如何比较另外两个呢?他们向我展示了相似的峰,只有很小的差异。

【问题讨论】:

    标签: javascript hash hash-function


    【解决方案1】:

    您可以通过简单地检查哪个具有较少的因子来比较其他两个,因为素数具有较少的因子用于散列。

    之所以两者的差异可以忽略不计,主要是因为你使用的哈希函数。您的散列函数已经给出了分布良好的值。但由于问题是关于直接比较。最好的方法是选择素数为 mod 887 的那个

    cs.stackexchange 中对此有很好的解释

    请访问此链接了解更多信息 https://cs.stackexchange.com/questions/11029/why-is-it-best-to-use-a-prime-number-as-a-mod-in-a-hashing-function

    还有更多关于模块化散列的详细信息 https://algs4.cs.princeton.edu/34hash/

    【讨论】:

    • 嗨 karthick 有趣的是,质数不是练习的正确答案,它是 900 因为这代表所有 900 个桶,你想澄清为什么应该使用质数还是你也认为900更好?
    猜你喜欢
    • 2021-01-19
    • 2016-03-25
    • 2011-02-27
    • 2011-12-10
    • 2017-01-22
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    相关资源
    最近更新 更多