谈谈hash算法

哈希算法的设计是一个需要考虑许多因素的复杂问题。然而对于某些要求不高的场景,我们也能设计一些简 单的哈希算法。

加法哈希:对输入的每个字符的 ASCII 码进行相加,将得到的总和作为哈希值。

乘法哈希:利用了乘法的不相关性,每轮乘以一个常数,将各个字符的 ASCII 码累积到哈希值中。

异或哈希:将输入数据的每个元素通过异或操作累积到一个哈希值中。

**旋转哈希 **:将每个字符的 ASCII 码累积到一个哈希值中,每次累积之前都会对哈希值进行旋转操作

1. 简单哈希算法代码实例

c++ 复制代码
/* 加法哈希 */
int addHash(string key) {
	long long hash = 0;
	const int MODULUS = 1000000007;
	for (unsigned char c : key) {
		hash = (hash + (int)c) % MODULUS;
	}
	return (int)hash;
}

/* 乘法哈希 */
int mulHash(string key) {
    long long hash = 0;
    const int MODULUS = 1000000007;
    for (unsigned char c : key) {
    	hash = (31 * hash + (int)c) % MODULUS;
    }
    return (int)hash;
}

/* 异或哈希 */
int xorHash(string key) {
    int hash = 0;
    const int MODULUS = 1000000007;
    for (unsigned char c : key) {
    	hash ^= (int)c;
    }
    return hash & MODULUS;
}

/* 旋转哈希 */
int rotHash(string key) {
    long long hash = 0;
    const int MODULUS = 1000000007;
    for (unsigned char c : key) {
    	hash = ((hash << 4) ^ (hash >> 28) ^ (int)c) % MODULUS;
    }
    return (int)hash;
}
  • 每种哈希算法的最后一步都是对大质数 1000000007 取模,以确保哈希值在合适的范围内。大家知道为什么要对质数取模,或者说对合数取模的弊端是什么?结论:当我们使用大质数作为模数时,可以因为质数不会与其他数字存在公约数,可以减少因取模操作而产生的周期性模式,从而避免哈希冲突,最大化地保证哈希值的均匀分布。

2.常见哈希算法

以上介绍的简单哈希算法都比较脆弱,远远没有达到哈希算法的设计目标。例如,由于加法和 异或满足交换律,因此加法哈希和异或哈希无法区分内容相同但顺序不同的字符串,这可能会加剧哈希冲突, 并引起一些安全问题。

  • 在实际中,我们通常会用一些标准哈希算法,例如 MD5、SHA‑1、SHA‑2、SHA3 等。它们可以将任意长度 的输入数据映射到恒定长度的哈希值。
    • MD5和SHA-1:已多次被成功攻击,因此它们被各类安全应用弃用。
    • SHA‑2 系列中的 SHA‑256 是最安全的哈希算法之一,仍未出现成功的攻击案例,因此常被用在各类安全应用与协议中。
    • SHA‑3 相较 SHA‑2 的实现开销更低、计算效率更高,但目前使用覆盖度不如 SHA‑2 系列。
MD5 SHA-1 SHA-2 SHA-3
问世时间 1992 1995 2002 2008
输出长度 128bits 160bits 256/512 bits 224/256/384/512 bits
哈希冲突 较多 较多 很少 很少
安全等级 低,已被成功攻击 低,已被成功攻击
应用情况 已被弃用,仍用于数据完整 性检查 已被弃用 加密货币交易验证、数字 签名等 可用于替代 SHA‑2

3.数据结构的哈希值

  • 我们知道,哈希表的 key 可以是整数、小数或字符串等数据类型。编程语言通常会为这些数据类型提供内置 的哈希算法,用于计算哈希表中的桶索引。以 Python 为例,我们可以调用 hash() 函数来计算各种数据类型 的哈希值。

    • 整数和布尔量的哈希值就是其本身。
    • 浮点数和字符串的哈希值计算较为复杂,有兴趣的同学请自行学习。
    • 元组的哈希值是对其中每一个元素进行哈希,然后将这些哈希值组合起来,得到单一的哈希值。
    • 对象的哈希值基于其内存地址生成。通过重写对象的哈希方法,可实现基于内容生成哈希值。
  • 不同编程语言的内置哈希值计算函数的定义和方法不同,以下为C++语言的哈希函数 std:hash(),它仅提供基本数据类型的哈希值计算,数组、对象的哈希值计算需要自行实现

    C++ 复制代码
    // 整数 3 的哈希值为 3
    int num = 3;
    size_t hashNum = hash<int>()(num);
    
    // 布尔量 1 的哈希值为 1
    bool bol = true;
    size_t hashBol = hash<bool>()(bol);
    
    // 小数 3.14159 的哈希值为 4614256650576692846
    double dec = 3.14159;
    size_t hashDec = hash<double>()(dec);
    
    // 字符串 Hello 算法 的哈希值为 15466937326284535026
    string str = "Hello 算法";
    size_t hashStr = hash<string>()(str);
相关推荐
无限进步_1 分钟前
基于顺序表的通讯录系统设计与实现
c语言·开发语言·数据结构·c++·后端·算法·visual studio
.格子衫.11 分钟前
028动态规划之字符串DP——算法备赛
算法·动态规划·字符串
小此方16 分钟前
Re:从零开始的链式二叉树:建树、遍历、计数、查找、判全、销毁全链路实现与底层剖析
c语言·数据结构·c++·算法
im_AMBER19 分钟前
Leetcode 65 固定长度窗口 | 中心辐射型固定窗口
笔记·学习·算法·leetcode
得物技术26 分钟前
项目性能优化实践:深入FMP算法原理探索|得物技术
前端·算法
FMRbpm27 分钟前
STL中栈的实现
数据结构·c++·算法
roman_日积跬步-终至千里29 分钟前
【模式识别与机器学习(3)】主要算法与技术(中篇:概率统计与回归方法)之贝叶斯方法(Bayesian)
算法·机器学习·回归
AI科技星32 分钟前
加速正电荷产生的电场、引力场与磁场变化率方向关系的数学求导验证——基于张祥前统一场论核心方程
数据结构·人工智能·经验分享·算法·机器学习·计算机视觉
zore_c1 小时前
【C语言】文件操作详解1(文件的打开与关闭)
c语言·开发语言·数据结构·c++·经验分享·笔记·算法
资深web全栈开发1 小时前
[特殊字符] LeetCode 2141:如何让 N 台电脑续航最久?——“二分答案“套路一文讲透
算法·leetcode