第 05 讲:哈希函数的本质及哈希游戏平台生成方式
哈希游戏作为一种新兴的区块链应用,它巧妙地结合了加密技术与娱乐,为玩家提供了全新的体验。万达哈希平台凭借其独特的彩票玩法和创新的哈希算法,公平公正-方便快捷!万达哈希,哈希游戏平台,哈希娱乐,哈希游戏
从本讲开始将进入数据结构的全新篇章:哈希表。若要构建出哈希表这种数据结构的话,会涉及到两个重要的算法,分别是哈希函数和解决哈希碰撞的算法。在接下来的第 05 和 06 讲中,我们会先一起研究哈希函数的本质以及它的应用;在第 07 和 08 讲中,将会探讨当遇到哈希碰撞时应该如何解决,以及哈希表在实战中的应用。 #### 哈希表与哈希函数 说到哈希表,其实本质上是一个数组。通过前面的学习我们知道了,如果要访问一个数组中某个特定的元素,那么需要知道这个元素的索引。例如,我们可以用数组来记录自己好友的电线 指向的元素记录着 A 的电线 指向的元素记录着 B 的电话号码,以此类推。 而当这个数组非常大的时候,全凭记忆去记住哪个索引记录着哪个好友的号码是非常困难的。这时候如果有一个函数,可以将我们好友的姓名作为一个输入,然后输出这个好友的号码在数组中对应的索引,是不是就方便了很多呢?这样的一种函数,其实就是哈希函数。哈希函数的定义是将任意长度的一个对象映射到一个固定长度的值上,而这个值我们可以称作是哈希值(Hash Value)。 哈希函数一般会有以下三个特性: * 任何对象作为哈希函数的输入都可以得到一个相应的哈希值; * 两个相同的对象作为哈希函数的输入,它们总会得到一样的哈希值; * 两个不同的对象作为哈希函数的输入,它们不一定会得到不同的哈希值。 对于哈希函数的前两个特性,比较好理解,但是对于第三种特性,我们应该如何解读呢?那下面就通过一个例子来说明。 我们按照 Java String 类里的哈希函数公式(即下面的公式)来计算出不同字符串的哈希值。String 类里的哈希函数是通过 hashCode 函数来实现的,这里假设哈希函数的字符串输入为 s,所有的字符串都会通过以下公式来生成一个哈希值:  细心的你一定发现了,上面所讲到的 Java String 类里的 hashCode 函数,一直在使用一个 31 这样的正整数来进行计算,这是为什么呢?下面一起来研究一下 Java Openjdk-jdk11 中 String.java 的源码(源码链接),看看这么做有什么好处。 ``` public int hashCode() { int h = hash; if (h == 0 && value.length 0) { hash = h = isLatin1() ? StringLatin1.hashCode(value) : StringUTF16.hashCode(value); } return ``` 可以看到,String 类的 hashCode 函数依赖于 StringLatin1 和 StringUTF16 类的具体实现。而 StringLatin1 类中的 hashCode 函数(源码链接)和 StringUTF16 类中的 hashCode 函数(源码链接)所表达的算法其实是一致的。 StringLatin1 类中的 hashCode 函数如下面所示: ``` public static int hashCode(byte[] value) { int h = 0; for (byte v : value) { h = 31 * h + (v } return h ``` StringUTF16 类中的 hashCode 函数如下面所示: ``` public static int hashCode(byte[] value) { int h = 0; int length = value.length 1; for (int i = 0; i length; i++) { h = 31 * h + getChar(value, i); } return h ``` 一个好的哈希函数算法都希望尽可能地减少生成出来的哈希值会造成哈希碰撞的情况。 Goodrich 和 Tamassia 这两位计算机科学家曾经做过一个实验,他们对超过 50000 个英文单词进行了哈希值运算,并使用常数 31、33、37、39 和 41 作为乘数因子,每个常数所算出的哈希值碰撞的次数都小于 7 个。但是最终选择 31 还是有着另外几个原因。 从数学的角度来说,选择一个质数(Prime Number)作为乘数因子可以让哈希碰撞减少。其次,我们可以看到在上面的两个 hashCode 源码中,都有着一条 31 * h 的语句,这条语句在 JVM 中其实都可以被自动优化成“(h 5) - h”这样一条位运算加上一个减法指令,而不必执行乘法指令了,这样可以大大提高运算哈希函数的效率。 所以最终 31 这个乘数因子就被一直保留下来了。 * [ ] 区块链挖矿的本质 通过上面的学习,相信你已经对哈希函数有了一个比较好的了解了。可能也发现了,哈希函数从输入到输出,我们可以按照函数的公式算法,很快地计算出哈希值。但是如果告诉你一个哈希值,即便给出了哈希函数的公式也很难算得出原来的输入到底是什么。例如,还是按照上面 String 类的 hashCode 函数的计算公式: ) 这样两次的哈希运算,来找出满足一定规则的字符串出来。 比方说,比特币会要求找出通过上面 SHA256(SHA256(x)) 计算之后的哈希值,这个 256 位的哈希值中的前 50 位都必须为 0 ,谁先找到满足这个要求的输入值 x,就等于“挖矿”成功,给予奖励一个比特币。我们知道,即便知道了哈希值,也很难算出这个 x 是什么,所以只能一个一个地去尝试。而市面上所说的挖矿机,其原理是希望能提高运算的速度,让“矿工”尽快地找到这个 x 出来。
第 08 讲:哈希表在 Facebook 和 Pinterest 中的应用
第 12 讲:LSM 树在 Apache HBase 等存储系统中的应用
第 18讲:高并发数据结构在 Instagram 与 Twitter 中的应用