What is Hash?
Hash 既可以指数据结构中的哈希表(hash table),也可以指常见的加密散列算法(hash algorithm)。
Hash表,Hash算法,虽然都叫Hash, 但是 哈希表和哈希算法是不同的概念,它们只是都利用了散列函数的思想而已。
下面来分享两者的区别,哈希表和哈希算法有以下几个主要的不同点:
哈希表和哈希算法是什么:
- 哈希表是一种数据结构,用于存储和快速查找键值对。
- 哈希算法则是一种密码学算法,用于将任意长度的输入转换为固定长度的输出。
目的不同:
- 哈希表的目的是实现高效的数据存储和查找。
- 哈希算法的目的是提供信息摘要、数字签名等加密安全功能。
可逆性:
- 哈希表的值是可逆的,可以通过键找到对应的值;
- 哈希算法的输出是不可逆的,无法从散列值推导出原始输入。
在实际应用中,它们各有优势:
哈希表优势:
- 提供O(1)时间复杂度的查找、插入、删除操作,效率高。
- 应用广泛,如缓存、索引、数据去重等。
哈希算法优势:
- 抗碰撞性强,安全性高,广泛应用于加密、数字签名等安全领域。
- 可压缩任意长度的数据到固定长度,便于存储和传输。
- 单向性强,不可逆,适合信息摘要等安全应用。
哈希算法的两个特性:
- 不可逆性:无法对一个散列值做逆向操作来获取其原始数据;
- 唯一性:不同的数据其计算得出的散列值永远不同,而同一输入计算出的散列值永远一样。
散列函数
散列算法是一种数据结构和算法,它将任意长度的输入数据转换成固定长度的输出数据,称为散列值或者摘要。散列算法的工作原理通常包括以下几个步骤:
-
预处理输入数据:
- 在某些情况下,需要先对输入数据进行填充或格式化,使其满足算法的要求,例如 MD5 算法要求数据长度是 448 位的整数倍。
-
初始化状态值:
- 大多数散列算法会使用一组固定的初始值作为状态寄存器的初始值,这些值通常是常数或者前一次计算的结果。
-
迭代压缩函数:
- 散列算法会反复对输入数据进行处理和压缩。每个压缩步骤都会使用不同的常数、逻辑运算或者数学运算,将当前状态值和当前数据块进行变换,得到新的状态值。
-
输出散列值:
- 经过多轮的压缩计算后,最终会得到一个固定长度的散列值,这就是算法的输出结果。
不同的散列算法在具体实现上会有所不同,比如 MD5 使用 4 个 32 位寄存器,SHA-256 使用 8 个 32 位寄存器。但基本工作原理是相同的:通过预处理、迭代压缩、输出结果等步骤,将任意长度的输入转换成固定长度的输出。
它是怎么防止别逆向回去的?
假设我们使用 SHA-256 散列算法,输入字符串 "hello world" 怎么转换为散列值?
中间不可逆的原理是什么?
todo
Hash表的操作都是O(1) ?
一个简单的原理展示:
-
计算机只需调用哈希函数(输入键值);
准备好哈希映射表,以下面这个字母和数字的简单映射为例:
A = 1
B = 2
C = 3
D = 4
E = 5
...以此类推。 -
计算键的哈希值;
计算机会对键使用哈希函数。假设使用“乘法”函数,结果如下:
BAD = 2 × 1 × 4 = 8 -
跳转到对应索引并读取值即可;
-
code example:
Map<String, String> map = new HashMap<>(); map.put("BAD", "evil"); String value = map.get("BAD"); System.out.println(value);
out:
evil
什么是散列函数思想?
- 将任意长度的输入映射到固定长度的输出(称为散列值或哈希值);
- 散列函数应该尽可能均匀地分布输入到整个输出范围,即具有良好的分散性(dispersion)。这样可以减少冲突的概率;
- 散列函数应该是高效的,即计算速度快,便于实现;
- 散列函数应该尽可能满足单向性和抗碰撞性。单向性指无法从散列值推导出原始输入,抗碰撞性指很难找到两个不同的输入产生相同的散列值。