目录
前言:
MurmurHash 介绍
各语言版本Murmurhash算法实现
C# 版本的Murmurhash算法实现
c/c++版本Murmurhash算法实现
java版本Murmurhash算法实现
对与C#或其他语言,我们有时需要计算hashCode或计算一串字符串、类的唯一值。我们知道不同的语言版本所计算方法不一,但是都有相应的性能问题。MurmurHash 对于唯一值的计算相对就快速很多。
MurmurHash 是一种高性能的哈希算法,由 Austin Appleby 在 2008 年创建。它是一种非加密哈希算法,可以快速地计算出任意数据的哈希值。
MurmurHash 算法的特点是快速、高效、低碰撞、低冲突,适用于各种哈希表、哈希集合、哈希映射等数据结构。它的哈希值分布均匀,哈希冲突率低,能够更好地处理哈希碰撞和哈希冲突。
MurmurHash 算法的原理是将输入数据分成若干个块,每个块都使用不同的哈希函数计算出一个哈希值,然后将这些哈希值进行混合和运算,得到最终的哈希值。MurmurHash 算法使用了一些技巧来保证哈希值的均匀分布,例如使用了随机数种子、对哈希值进行了混淆等。
MurmurHash 算法有多个版本,包括 32 位和 64 位版本,也有多个变种,例如 MurmurHash3、MurmurHash2、MurmurHash1 等。MurmurHash 算法的实现语言包括 C++、Java、C#、Python 等。
总之,MurmurHash 算法是一种高效、低冲突、低碰撞的哈希算法,适用于各种哈希表、哈希集合、哈希映射等数据结构,是一个非常优秀的哈希算法。
MurmurHash 算法相比于 hashCode 算法有以下优点:
更好的哈希性能:MurmurHash 算法在哈希性能方面比 hashCode 算法更优秀,因为它能够快速地计算出任意数据的哈希值。MurmurHash 算法的哈希性能取决于数据的分布情况,但是在大多数情况下,它都能够提供比较好的哈希性能。
更低的哈希冲突率:MurmurHash 算法在哈希冲突率方面比 hashCode 算法更优秀,因为它能够更好地处理哈希冲突。MurmurHash 算法使用了一些技巧来减少哈希冲突,例如使用了两个不同的哈希函数、对哈希值进行了混淆等。
更好的分布性:MurmurHash 算法的哈希值在分布性方面比 hashCode 算法更优秀,因为它能够更好地处理数据的分布情况。MurmurHash 算法使用了一些技巧来保证哈希值的均匀分布,例如使用了随机数种子、对哈希值进行了混淆等。
更少的哈希碰撞:MurmurHash 算法在哈希碰撞方面比 hashCode 算法更优秀,因为它能够更好地处理哈希碰撞。MurmurHash 算法使用了一些技巧来减少哈希碰撞,例如使用了两个不同的哈希函数、对哈希值进行了混淆等。
综上所述,MurmurHash 算法相比于 hashCode 算法具有更好的哈希性能、更低的哈希冲突率、更好的分布性和更少的哈希碰撞。因此,在需要高效的哈希算法时,MurmurHash 算法是一个更好的选择。
使用第三方库 MurmurHash.Net 实现 MurmurHash 算法的示例代码:
using MurmurHash;
byte[] data = Encoding.UTF8.GetBytes("hello world");
uint seed = 0;
uint hash = MurmurHash3.Hash32(data, seed);
在上面的代码中,我们使用 MurmurHash3.Hash32()
方法计算输入数据的哈希值。data
是输入数据的字节数组,seed
是一个种子值,hash
是计算出的哈希值。
如果您想自己实现 MurmurHash 算法,可以参考以下代码:
public static class MurmurHash {
public static uint Hash32(byte[] data, uint seed) {
const uint c1 = 0xcc9e2d51;
const uint c2 = 0x1b873593;
const uint r1 = 15;
const uint r2 = 13;
const uint m = 5;
const uint n = 0xe6546b64;
uint hash = seed;
uint len = (uint)data.Length;
int pos = 0;
while (len >= 4) {
uint k = BitConverter.ToUInt32(data, pos);
k *= c1;
k = (k << r1) | (k >> (32 - r1));
k *= c2;
hash ^= k;
hash = (hash << r2) | (hash >> (32 - r2));
hash = hash * m + n;
len -= 4;
pos += 4;
}
if (len > 0) {
uint k = 0;
for (int i = 0; i < len; i++) {
k |= (uint)data[pos + i] << (8 * i);
}
k *= c1;
k = (k << r1) | (k >> (32 - r1));
k *= c2;
hash ^= k;
}
hash ^= (uint)data.Length;
hash ^= hash >> 16;
hash *= 0x85ebca6b;
hash ^= hash >> 13;
hash *= 0xc2b2ae35;
hash ^= hash >> 16;
return hash;
}
}
在上面的代码中,我们实现了 MurmurHash 算法的 32 位版本。data
是输入数据的字节数组,seed
是一个种子值,hash
是计算出的哈希值。
#include
#include
uint32_t murmurhash(const void* key, int len, uint32_t seed) {
const uint32_t c1 = 0xcc9e2d51;
const uint32_t c2 = 0x1b873593;
const uint32_t r1 = 15;
const uint32_t r2 = 13;
const uint32_t m = 5;
const uint32_t n = 0xe6546b64;
const uint8_t* data = (const uint8_t*)key;
const int nblocks = len / 4;
uint32_t hash = seed;
for (int i = 0; i < nblocks; i++) {
uint32_t k = *(uint32_t*)(data + i * 4);
k *= c1;
k = (k << r1) | (k >> (32 - r1));
k *= c2;
hash ^= k;
hash = (hash << r2) | (hash >> (32 - r2));
hash = hash * m + n;
}
const uint8_t* tail = (const uint8_t*)(data + nblocks * 4);
uint32_t k = 0;
switch (len & 3) {
case 3:
k ^= tail[2] << 16;
case 2:
k ^= tail[1] << 8;
case 1:
k ^= tail[0];
k *= c1;
k = (k << r1) | (k >> (32 - r1));
k *= c2;
hash ^= k;
}
hash ^= len;
hash ^= hash >> 16;
hash *= 0x85ebca6b;
hash ^= hash >> 13;
hash *= 0xc2b2ae35;
hash ^= hash >> 16;
return hash;
}
在上面的代码中,我们实现了 MurmurHash 算法的 32 位版本。key
是输入数据的指针,len
是输入数据的长度,seed
是一个种子值,hash
是计算出的哈希值。
在 Java 中,我们可以使用 Guava 库或自己实现 MurmurHash 算法。
以下是一个使用 Guava 库实现 MurmurHash 算法的示例代码:
import com.google.common.hash.Hashing;
byte[] data = "hello world".getBytes();
int seed = 0;
int hash = Hashing.murmur3_32(seed).hashBytes(data).asInt();
在上面的代码中,我们使用 Hashing.murmur3_32()
方法创建一个 MurmurHash 算法的实例,然后使用 hashBytes()
方法计算输入数据的哈希值。data
是输入数据的字节数组,seed
是一个种子值,hash
是计算出的哈希值。
如果您想自己实现 MurmurHash 算法,可以参考以下代码:
public static int murmurhash(byte[] data, int seed) {
final int c1 = 0xcc9e2d51;
final int c2 = 0x1b873593;
final int r1 = 15;
final int r2 = 13;
final int m = 5;
final int n = 0xe6546b64;
int hash = seed;
int len = data.length;
int pos = 0;
while (len >= 4) {
int k = (data[pos] & 0xff) | ((data[pos + 1] & 0xff) << 8) | ((data[pos + 2] & 0xff) << 16) | ((data[pos + 3] & 0xff) << 24);
k *= c1;
k = (k << r1) | (k >>> (32 - r1));
k *= c2;
hash ^= k;
hash = (hash << r2) | (hash >>> (32 - r2));
hash = hash * m + n;
len -= 4;
pos += 4;
}
if (len > 0) {
int k = 0;
for (int i = 0; i < len; i++) {
k |= (data[pos + i] & 0xff) << (8 * i);
}
k *= c1;
k = (k << r1) | (k >>> (32 - r1));
k *= c2;
hash ^= k;
}
hash ^= data.length;
hash ^= hash >>> 16;
hash *= 0x85ebca6b;
hash ^= hash >>> 13;
hash *= 0xc2b2ae35;
hash ^= hash >>> 16;
return hash;
}
在上面的代码中,我们实现了 MurmurHash 算法的 32 位版本。data
是输入数据的字节数组,seed
是一个种子值,hash
是计算出的哈希值。