MurmurHash的定义
MurmurHash 是一种非加密型哈希函数,适用于一般的哈希检索操作。由Austin Appleby在2008年发明,并出现了多个变种,都已经发布到了公有领域(public domain)。与其它流行的哈希函数相比,对于规律性较强的key,MurmurHash的随机分布特征表现更良好。
MurmurHash的特点
- 高速度: MurmurHash3 被设计为快速计算哈希值,特别适用于需要高性能的场景。它的实现通常使用了有效的位运算和数值操作,以确保在处理大量数据时仍能保持高效率。
- 低碰撞: MurMurHash3 128 位版本哈希值是 128 位的,在数据量只有千万级别的情况下,基本不用担心碰撞。
- 良好的分布性: MurmurHash3 提供了良好的随机性和分布特性。这意味着不同的输入数据在哈希后,其哈希值分布均匀,减少了哈希冲突的可能性。这对于哈希表、散列数据结构等需要快速检索的应用至关重要。
- 适用性广泛: 由于其速度和分布性,MurmurHash3 可以应用于各种场景,包括分布式系统、缓存系统、数据检验和索引等。它在这些领域中可以提供快速且有效的哈希功能。
- 可配置性: MurmurHash3 允许用户通过调整种子值和其他参数来定制哈希算法的行为。这种灵活性使得可以根据具体需求进行优化,例如调整哈希长度或者初始化种子值,以适应不同的应用场景和数据集合。
- 非加密性: MurmurHash3 是一种非加密的哈希函数,它专注于提供高速和良好的分布特性,但不适用于需要强加密保护的数据传输或存储场景。对于这类需求,应使用专门的加密哈希函数。
MurmurHash3的实现原理
初始化参数
- 种子值(Seed): MurmurHash3 使用一个种子值(seed),这个种子值可以用来初始化哈希计算的状态。不同的种子值将产生不同的哈希结果,这对于哈希表的冲突处理很有用。
- 常数: 算法中使用一些预定义的常数,这些常数有助于确保哈希的混合和扩散性。
主循环
主循环是 MurmurHash3 哈希计算的核心部分,通常包括以下步骤:
按 4 字节处理数据: 将输入数据按 4 字节(32 位)一组进行处理。如果最后一个块不足 4 字节,则使用特殊处理方式。
混合(Mixing)操作: 对每个 4 字节的块进行混合操作,以确保输入数据的高低位均匀地分布到输出哈希值中。这通常涉及位运算、乘法、异或等操作。
旋转(Rotation)和混合: MurmurHash3 使用了一些位级操作和旋转操作,以增加哈希的随机性和分散性。
最终化
在处理完所有输入数据后,对哈希值进行最终化操作。这些操作通常包括最后一次混合、再次使用常数和种子值进行混合,以确保最终的哈希值具有良好的随机性和分布性。
输出
最终得到的哈希值是一个固定长度(通常是 32 位或 64 位)的整数,可以作为输入数据的唯一标识或索引值使用。
MurmurHash的Go语言实现
go
const (
c1 = 0xcc9e2d51
c2 = 0x1b873593
r1 = 15
r2 = 13
m = 5
n = 0xe6546b64
)
func MurmurHash3(key []byte, seed uint32) uint32 {
var h1 = seed
var k1 uint32
var chunk uint32
blocks := len(key) / 4
for i := 0; i < blocks; i++ {
chunk = uint32(key[i*4]) | uint32(key[i*4+1])<<8 | uint32(key[i*4+2])<<16 | uint32(key[i*4+3])<<24
k1 = chunk
k1 *= c1
k1 = bits.RotateLeft32(k1, r1)
k1 *= c2
h1 ^= k1
h1 = bits.RotateLeft32(h1, r2)
h1 = h1*m + n
}
tail := key[blocks*4:]
switch len(tail) {
case 3:
h1 ^= uint32(tail[2]) << 16
fallthrough
case 2:
h1 ^= uint32(tail[1]) << 8
fallthrough
case 1:
h1 ^= uint32(tail[0])
h1 *= c1
h1 = bits.RotateLeft32(h1, r1)
h1 *= c2
}
h1 ^= uint32(len(key))
h1 ^= h1 >> 16
h1 *= 0x85ebca6b
h1 ^= h1 >> 13
h1 *= 0xc2b2ae35
h1 ^= h1 >> 16
return h1
}
func main() {
s := "video/BV1yT4y1a7tD/?spm_id_from=333.337.search-card.all.click&vd_source=3cd3e5853cdff0baa992698bfe4286f6"
//转换为byte类型
arrayOfString := []byte(s)
resultTen := MurmurHash3(arrayOfString, 0)
fmt.Println(resultTen)
}
代码解析
常量定义
- c1, c2: 用于混合和乘法的常数。
- r1, r2: 用于左移位操作的位移量。
- m, n: 用于混合操作的常数。
MurmurHash3函数
- MurmurHash3函数接受两个参数:key是待哈希的字节数组,seed是哈希种子,用于初始化哈希值。
- h1 是哈希结果的中间值,初始化为seed。
- k1 是每个处理的块的哈希键。
- chunk 是每次处理的四个字节的数据块。
哈希计算过程
处理数据:
- 将输入的字节数组分成4字节的块,按顺序处理。
- 计算每个块的哈希键 k1,应用一系列乘法、位移和异或操作。
- 将结果与中间值 h1 进行混合和旋转操作。
- 处理剩余不足4字节的部分(尾部):
处理剩余尾部:
如果输入的字节数组长度不是4的整数倍,处理剩余的部分。这部分通过一系列的位移、乘法和异或操作来处理,确保整个字节数组都被考虑在内。
最终对哈希值进行最后的混合和压缩,确保输出的哈希值分布均匀和具有良好的性质。