加权哈希组合

Weighted hash combine

本文关键字:组合 哈希 加权      更新时间:2023-10-16

这是如何组合两个哈希值的一个小变化,因为我希望结果哈希值更多地受其中一个输入的影响。

对于大致对称的情况,我们有这样的算法:boost::hash_combine:
template <class T>
inline void hash_combine(std::size_t& seed, const T& v)
{
  std::hash<T> hasher;
  seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
}

我正在寻找一个加权版本,也许界面会类似:

uint64_t weighted_hash_combine(uint64_t hashA, uint16 weightA, uint64_t hashB, uint16 weightB);

前提是输出哈希中某位受到输入哈希中某位变化影响的概率是weightA与weightB之比的函数。

这将允许我改进非平衡树的树哈希算法。这里介绍了对树进行散列的一种更简单的方法,本质上是广度优先遍历,将每个散列(节点)推入一个累积值。这样做的问题是,最后一个被混合到组合散列中的节点将比第一个节点对结果的影响更大。

如果有一个合理的加权哈希组合,那么我可以根据每个哈希的节点数量对组合进行偏倚,并希望提高哈希函数的公平性。

到目前为止,我想到了:

uint64_t weighted_hash_combine(uint64_t hashA, uint16 weightA, uint64_t hashB, uint16 weightB)
{
  if (weightA > weightB)
  {
    return weighted_hash_combine(hashB,weightB,hashA,weightA);
  }
  uint64_t ratio = weightA / weightB;
  uint64_t combined = hashA;
  for (uint64_t i = 0; i < ratio; i++)
  {
     hash_combine(combined, hashB);
  }
  return combined;
 }       

这是相当缺乏数值复杂性,所以我希望社区可以回忆/发明一个更好的解决方案。

高级目标是在(size或)哈希值不同时缩短树之间的相等性测试,因为它们通常只在一个或两个叶子中不同,并且没有好的方法来估计哪个

哈希不是这样工作的。当您正确地组合哈希时,更改哈希可以保证更改组合哈希,实际上,通过更改哈希,您可以完全确定组合哈希的值。

最常用的组合是:

h = h1*P2 + h2*P1

其中P1和P2是不同的奇数素数(或1)。这将执行mod 2^32或mod 2^64取决于字的大小,但在这两种情况下,你可以通过选择h1h2使h成为任何你想要的值,无论我们像这样混合多少其他哈希值,这都不会消失。