我的想法:
方法一:
计算第一个2n 素数,其中n 是数组的长度。
设哈希 = 1。
对于 i = 0 到 n:如果位置 i 的位为 1,则将 hash 乘以 2ith 和 2i + 1st 素数。如果为 0,则仅将其乘以 2ith 。
方法 #2:
将二进制数组视为三进制。位为 0 => 三进制数为 0;位为 1 => 三进制数为 1;位不存在 => 三进制数为 2(前者有效,因为数组具有最大可能长度)。
使用此替换计算三进制数 - 结果将是唯一的。
这里有一些代码展示了这些算法在 C++ 中的实现,以及一个为每个长度为 0...18 的布尔数组生成散列的测试程序。我使用 C++11 类 std::unordered_map 以便每个哈希都是唯一的。因此,如果我们没有任何重复项(即,如果散列函数是完美的),我们应该得到集合中的 2 ^ 19 - 1 元素,which we do(我必须在 IDEone 上将整数更改为 unsigned long long,否则哈希并不完美——我怀疑这与 32 位和 64 位架构有关):
#include <unordered_set>
#include <iostream>
#define MAX_LEN 18
unsigned long prime_hash(const unsigned int *arr, size_t len)
{
/* first 2 * MAX_LEN primes */
static const unsigned long p[2 * MAX_LEN] = {
2, 3, 5, 7, 11, 13, 17, 19, 23,
29, 31, 37, 41, 43, 47, 53, 59, 61,
67, 71, 73, 79, 83, 89, 97, 101, 103,
107, 109, 113, 127, 131, 137, 139, 149, 151
};
unsigned long h = 1;
for (size_t i = 0; i < len; i++)
h *= p[2 * i] * (arr[i] ? p[2 * i + 1] : 1);
return h;
}
unsigned long ternary_hash(const unsigned int *arr, size_t len)
{
static const unsigned long p3[MAX_LEN] = {
1, 3, 9, 27,
81, 243, 729, 2187,
6561, 19683, 59049, 177147,
531441, 1594323, 4782969, 14348907,
43046721, 129140163
};
unsigned long h = 0;
for (size_t i = 0; i < len; i++)
if (arr[i])
h += p3[i];
for (size_t i = len; i < MAX_LEN; i++)
h += 2 * p3[i];
return h;
}
void int2barr(unsigned int *dst, unsigned long n, size_t len)
{
for (size_t i = 0; i < len; i++) {
dst[i] = n & 1;
n >>= 1;
}
}
int main()
{
std::unordered_set<unsigned long> phashes, thashes;
/* generate all possible bool-arrays from length 0 to length 18 */
/* first, we checksum the only 0-element array */
phashes.insert(prime_hash(NULL, 0));
thashes.insert(ternary_hash(NULL, 0));
/* then we checksum the arrays of length 1...18 */
for (size_t len = 1; len <= MAX_LEN; len++) {
unsigned int bits[len];
for (unsigned long i = 0; i < (1 << len); i++) {
int2barr(bits, i, len);
phashes.insert(prime_hash(bits, len));
thashes.insert(ternary_hash(bits, len));
}
}
std::cout << "prime hashes: " << phashes.size() << std::endl;
std::cout << "ternary hashes: " << thashes.size() << std::endl;
return 0;
}