如何合并两个哈希码?如何计算数组等集合的哈希码?
合并哈希码与数组哈希码实现
合并两个哈希码的方法
合并哈希码的核心是用质数加权减少碰撞概率,Java中普遍用31作为权重——它是质数,且31 * hash可等价为(hash << 5) - hash,移位运算比乘法更高效,还能保证哈希值分布均匀。
合并两个哈希码的通用实现:
function combineHash(hash1, hash2) { // 用|0确保结果为32位有符号整数,对齐Java的int类型逻辑 return (hash1 * 31 + hash2) | 0; }
若想避免乘法,也可以用移位实现等价逻辑:
function combineHash(hash1, hash2) { return ((hash1 << 5) - hash1 + hash2) | 0; }
基于N个哈希码计算集合哈希码(以数组为例)
参考Java的Arrays.hashCode()实现,我们可以遍历数组元素,逐步合并每个元素的哈希码。具体步骤:
- 初始化累积结果为1(Java数组哈希的标准初始值)
- 遍历数组每个元素:
- 元素为
null时,用0作为其哈希码 - 否则调用元素的
hashCode()方法获取哈希值
- 元素为
- 用合并公式更新累积结果
- 返回最终的累积哈希码
数组哈希码的具体实现
// 先定义cyrb53函数(来自Stack Overflow) function cyrb53(str, seed = 0) { let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed; for(let i = 0, ch; i < str.length; i++) { ch = str.charCodeAt(i); h1 = Math.imul(h1 ^ ch, 2654435761); h2 = Math.imul(h2 ^ ch, 1597334677); } h1 = Math.imul(h1 ^ (h1>>>16), 2246822507); h1 ^= Math.imul(h2 ^ (h2>>>13), 3266489909); h2 = Math.imul(h2 ^ (h2>>>16), 2246822507); h2 ^= Math.imul(h1 ^ (h1>>>13), 3266489909); return 4294967296 * (2097151 & h2) + (h1 >>> 0); } // 已实现的Number、String哈希方法 Number.prototype.hashCode = function() { return this } String.prototype.hashCode = function() { return cyrb53(this) } // 数组哈希方法实现 Array.prototype.hashCode = function() { let result = 1; for (const element of this) { const elementHash = element == null ? 0 : element.hashCode(); // 用Math.imul避免精度丢失,保证32位整数运算逻辑 result = Math.imul(result, 31) + elementHash; // 截断为32位有符号整数,和Java哈希规则对齐 result |= 0; } return result; }
补充说明
- 使用
Math.imul做乘法,避免JavaScript普通乘法的精度丢失,和Java的32位整数运算逻辑保持一致 - 处理
null元素的情况,符合Java的哈希规范 - 最终结果用
|0截断为32位有符号整数,模拟Java的int类型哈希码
内容的提问来源于stack exchange,提问作者Alex Craft
相关产品推荐
相关产品推荐

