您当前的位置:首页 > 电脑百科 > 程序开发 > 算法

一文读懂 MD5 算法

时间:2020-02-25 10:59:37  来源:  作者:

消息摘要算法是密码学算法中非常重要的一个分支,它通过对所有数据提取指纹信息以实现数据签名、数据完整性校验等功能,由于其不可逆性,有时候会被用做敏感信息的加密。消息摘要算法也被称为哈希(Hash)算法或散列算法。

任何消息经过散列函数处理后,都会获得唯一的散列值,这一过程称为 “消息摘要”,其散列值称为 “数字指纹”,其算法自然就是 “消息摘要算法”了。换句话说,如果其数字指纹一致,就说明其消息是一致的。

一文读懂 MD5 算法

 

(图片来源 —— https://zh.wikipedia.org/wiki/散列函數)

消息摘要算法的主要特征是加密过程不需要密钥,并且经过加密的数据无法被解密,目前可以解密逆向的只有 CRC32 算法,只有输入相同的明文数据经过相同的消息摘要算法才能得到相同的密文。消息摘要算法不存在密钥的管理与分发问题,适合于分布式网络上使用。消息摘要算法主要应用在 “数字签名” 领域,作为对明文的摘要算法。著名的摘要算法有 RSA 公司的 MD5 算法和 SHA-1 算法及其大量的变体。

1.1 消息摘要算法的特点

  • 无论输入的消息有多长,计算出来的消息摘要的长度总是固定的。 例如应用 MD5 算法摘要的消息有 128 个比特位,用 SHA-1 算法摘要的消息最终有 160 个比特位的输出,SHA-1的变体可以产生 192 个比特位和 256 个比特位的消息摘要。一般认为,摘要的最终输出越长,该摘要算法就越安全。
  • 消息摘要看起来是 “随机的”。 这些比特看上去是胡乱的杂凑在一起的,可以用大量的输入来检验其输出是否相同,一般,不同的输入会有不同的输出,而且输出的摘要消息可以通过随机性检验。 一般地,只要输入的消息不同,对其进行摘要以后产生的摘要消息也必不相同;但相同的输入必会产生相同的输出。
  • 消息摘要函数是单向函数,即只能进行正向的信息摘要,而无法从摘要中恢复出任何的消息,甚至根本就找不到任何与原信息相关的信息。
  • 好的摘要算法,没有人能从中找到 “碰撞” 或者说极度难找到,虽然 “碰撞” 是肯定存在的(碰撞即不同的内容产生相同的摘要)。

二、什么是 MD5 算法

MD5(Message Digest Algorithm 5,消息摘要算法版本5),它由 MD2、MD3、MD4 发展而来,由 Ron Rivest(RSA 公司)在 1992 年提出,目前被广泛应用于数据完整性校验、数据(消息)摘要、数据签名等。 MD2、MD4、MD5 都产生 16 字节(128 位)的校验值,一般用 32 位十六进制数表示。MD2 的算法较慢但相对安全,MD4 速度很快,但安全性下降,MD5 比 MD4 更安全、速度更快。

随着计算机技术的发展和计算水平的不断提高,MD5 算法暴露出来的漏洞也越来越多。1996 年后被证实存在弱点,可以被加以破解,对于需要高度安全性的数据,专家一般建议改用其他算法,如 SHA-2。2004 年,证实 MD5 算法无法防止碰撞(collision),因此不适用于安全性认证,如 SSL 公开密钥认证或是数字签名等用途。

2.1 MD5 特点

  • 稳定、运算速度快。
  • 压缩性:输入任意长度的数据,输出长度固定(128 比特位)。
  • 运算不可逆:已知运算结果的情况下,无法通过通过逆运算得到原始字符串。
  • 高度离散:输入的微小变化,可导致运算结果差异巨大。

2.2 MD5 散列

128 位的 MD5 散列在大多数情况下会被表示为 32 位十六进制数字。以下是一个 43 位长的仅 ASCII 字母列的MD5 散列:

MD5("The quick brown fox jumps over the lazy dog")= 9e107d9d372bb6826bd81d3542a419d6

即使在原文中作一个小变化(比如把 dog 改为 cog,只改变一个字符)其散列也会发生巨大的变化:

MD5("The quick brown fox jumps over the lazy cog")= 1055d3e698d289f2af8663725127bd4b

接着我们再来举几个 MD5 散列的例子:

         MD5("") -> d41d8cd98f00b204e9800998ecf8427e MD5("semlinker") -> 688881f1c8aa6ffd3fcec471e0391e4d   MD5("kakuqo") -> e18c3c4dd05aef020946e6afbf9e04ef

三、MD5 算法的用途

3.1 防止被篡改

3.1.1 文件分发防篡改

在互联网上分发软件安装包时,出于安全性考虑,为了防止软件被篡改,比如在软件安装程序中添加木马程序。软件开发者通常会使用消息摘要算法,比如 MD5 算法产生一个与文件匹配的数字指纹,这样接收者在接收到文件后,就可以利用一些现成的工具来检查文件完整性。

一文读懂 MD5 算法

 

(图片来源 —— https://en.wikipedia.org/wiki/MD5)

这里我们来举一个实际的例子,下图是 MySQL Community Server 8.0.19 版本的下载页,该下载页通过 MD5 算法分别计算出不同软件包的数字指纹,具体如下图所示:

一文读懂 MD5 算法

 

(图片来源 —— https://dev.mysql.com/downloads/mysql/)

当用户从官网上下载到对应的安装包之后,可以利用一些 MD5 校验工具对已下载的文件进行校验,然后比对最终的 MD5 数字指纹,若结果与官网公布的数字指纹一致,则表示该安装包未经过任何修改是安全的,基本可以放心安装。

3.1.2 消息传输防篡改

假设在网络上你需要发送电子文档给你的朋友,在文件发送前,先对文档的内容进行 MD5 运算,得出该电子文档的 “数字指纹”,并把该 “数字指纹” 随电子文档一同发送给对方。当对方接收到电子文档之后,也使用 MD5 算法对文档的内容进行哈希运算,在运算完成后也会得到一个对应 “数字指纹”,当该指纹与你所发送文档的 “数字指纹” 一致时,表示文档在传输过程中未被篡改。

3.2 信息保密

在互联网初期很多网站在数据库中以明文的形式存储用户的密码,这存在很大的安全隐患,比如数据库被黑客入侵,从而导致网站用户信息的泄露。针对这个问题,一种解决方案是在保存用户密码时,不再使用明文,而是使用消息摘要算法,比如 MD5 算法对明文密码进行哈希运算,然后把运算的结果保存到数据库中。使用上述方案,避免了在数据库中以明文方式保存密码,提高了系统的安全性,不过这种方案并不安全,后面我们会详细分析。

一文读懂 MD5 算法

 

当用户登录时,登录系统对用户输入的密码执行 MD5 哈希运算,然后再使用用户 ID 和密码对应的 MD5 “数字指纹” 进行用户认证。若认证通过,则当前的用户可以正常登录系统。用户密码经过 MD5 哈希运算后存储的方案至少有两个好处:

  • 防内部攻击:因为在数据库中不会以明文的方式保存密码,因此可以避免系统中用户的密码被具有系统管理员权限的人员知道。
  • 防外部攻击:网站数据库被黑客入侵,黑客只能获取经过 MD5 运算后的密码,而不是用户的明文密码。

四、MD5 算法使用示例

4.1 JAVA 示例

在 Java 中使用 MD5 算法很方便,可以直接使用 JDK 自带的 MD5 实现,也可以使用第三方库提供的 MD5 实现。下面我们将介绍 JDK、Bouncy Castle 和 Guava 的 MD5 使用示例。为了保证以下示例的正常运行,首先我们需要在 pom.xml 文件中添加 Bouncy Castle 和 Guava 的坐标:

<dependency>     <groupId>org.bouncycastle</groupId>     <artifactId>bcprov-jdk15on</artifactId>     <version>1.64</version></dependency><dependency>     <groupId>com.google.guava</groupId>     <artifactId>guava</artifactId>     <version>27.1-jre</version></dependency>

JDK 实现

public static void jdkMD5(String src) throws NoSuchAlgorithmException {    MessageDigest md = MessageDigest.getInstance("MD5");    byte[] md5Bytes = md.digest(src.getBytes());    System.out.println("JDK MD5:" + src + " -> " + bytesToHexString(md5Bytes));}

Bouncy Castle 实现

public static void bcMD5(String src) {    MD5Digest digest = new MD5Digest();    digest.update(src.getBytes(), 0, src.getBytes().length);    byte[] md5Bytes = new byte[digest.getDigestSize()];    digest.doFinal(md5Bytes, 0);    System.out.println("Bouncy Castle MD5:" + src + " -> " +       bytesToHexString(md5Bytes));}

Guava 实现

public static void guavaMD5(String src) {    HashFunction hf = Hashing.md5();    HashCode hc = hf.newHasher().putString(src, Charset.defaultCharset()).hash();    System.out.println("Guava MD5:" + src + " -> " + hc);}

在 JDK 实现和 Bouncy Castle 实现的示例中使用了 bytesToHexString 方法,该方法用于把字节数组转换成十六进制,它的具体实现如下:

private static String bytesToHexString(byte[] src) {    StringBuilder stringBuilder = new StringBuilder();    if (src == null || src.length <= 0) {         return null;    }    for (int i = 0; i < src.length; i++) {        int v = src[i] & 0xFF;        String hv = Integer.toHexString(v);        if (hv.length() < 2) {            stringBuilder.Append(0);        }        stringBuilder.append(hv);    }    return stringBuilder.toString();}

介绍完 MD5 算法不同的实现,下面我们来测试一下上述的方法:

public static void main(String[] args) throws NoSuchAlgorithmException {   jdkMD5("123");   bcMD5("123");   guavaMD5("123");}

以上示例代码正常运行后,在控制台中会输出以下结果:

JDK MD5:123 -> 202cb962ac59075b964b07152d234b70Bouncy Castle MD5:123 -> 202cb962ac59075b964b07152d234b70Guava MD5:123 -> 202cb962ac59075b964b07152d234b70

4.2 Node.js 示例

在 Node.js 环境中,我们可以使用 crypto 原生模块提供的 md5 实现,当然也可以使用主流的 MD5 第三方库,比如 md5 这个可以同时运行在服务端和客户端的第三方库。与 Java 示例一样,在介绍具体使用前,我们需要提前安装 md5 这个第三方库,具体安装方式如下:

$ npm install md5 --save

Node.js Crypto 实现

const crypto = require('crypto'); const msg = "123";function md5(data){  const hash = crypto.createHash('md5');  return hash.update(data).digest('hex');}console.log("Node.js Crypto MD5:" + msg + " -> " + md5(msg));

Node.js MD5 第三方库实现

const md5 = require('md5');const msg = "123";console.log("MD5 Lib MD5:" + msg + " -> " + md5(msg));

以上示例代码正常运行后,在控制台中会输出以下结果:

Node.js Crypto MD5:123 -> 202cb962ac59075b964b07152d234b70MD5 Lib MD5:123 -> 202cb962ac59075b964b07152d234b70

五、MD5 算法的缺陷

哈希碰撞是指不同的输入却产生了相同的输出,好的哈希算法,应该没有人能从中找到 “碰撞” 或者说极度难找到,虽然 “碰撞” 是肯定存在的。

2005 年山东大学的王小云教授发布算法可以轻易构造 MD5 碰撞实例,此后 2007 年,有国外学者在王小云教授算法的基础上,提出了更进一步的 MD5 前缀碰撞构造算法 “chosen prefix collision”,此后还有专家陆续提供了MD5 碰撞构造的开源的库。

2009 年,中国科学院的谢涛和冯登国仅用了 220.96 的碰撞算法复杂度,破解了 MD5 的碰撞抵抗,该攻击在普通计算机上运行只需要数秒钟。

MD5 碰撞很容易构造,基于 MD5 来验证数据完整性已不可靠,考虑到近期谷歌已成功构造了 SHA-1(英语:Secure Hash Algorithm 1,中文名:安全散列算法1)的碰撞实例,对于数据完整性,应使用 SHA256 或更强的算法代替。

下面我们来看个简单的 MD5 碰撞示例:

HEX(十六进制)样本A1

4dc968ff0ee35c209572d4777b721587d36fa7b21bdc56b74a3dc0783e7b9518afbfa200a8284bf36e8e4b55b35f427593d849676da0d1555d8360fb5f07fea2

HEX(十六进制)样本A2

4dc968ff0ee35c209572d4777b721587d36fa7b21bdc56b74a3dc0783e7b9518afbfa202a8284bf36e8e4b55b35f427593d849676da0d1d55d8360fb5f07fea2

两个样本之间的差异如下图所示:

一文读懂 MD5 算法

 

下面我们来通过 Java 代码实际验证一下样本 A1 和样本 A2 经过 MD5 运算后输出的结果是否一致:

jdkMd5Hex 方法

public static void jdkMd5Hex(String hexStr) throws NoSuchAlgorithmException {    byte[] bytes = hexStringToBytes(hexStr);    MessageDigest md = MessageDigest.getInstance("MD5");    byte[] md5Bytes = md.digest(bytes);    System.out.println("JDK MD5:" + hexStr + " -> " + bytesToHexString(md5Bytes));}

hexStringToBytes 方法

public static byte[] hexStringToBytes(String s) {    int len = s.length();    byte[] data = new byte[len / 2];    for (int i = 0; i < len; i += 2) {        data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)          + Character.digit(s.charAt(i+1), 16));    }    return data;}

main 方法

public static void main(String[] args) throws NoSuchAlgorithmException {    jdkMd5Hex("4dc968ff..."); //样本A    jdkMd5Hex("4dc968ff..."); //样本B}

以上示例代码正常运行后,在控制台中会输出以下结果:

JDK MD5:4dc968ff... -> 008ee33a9d58b51cfeb425b0959121c9JDK MD5:4dc968ff... -> 008ee33a9d58b51cfeb425b0959121c9

如果你对其它 MD5 碰撞的样本感兴趣,可以查看 MD5碰撞的一些例子 这篇文章。由于基于 MD5 来验证数据完整性已不可靠,因此很多人都熟悉的 Node.js 使用了 SHA256 算法来确保数据的完整性。

一文读懂 MD5 算法

 

(图片来源 —— https://nodejs.org/dist/v12.14.1/SHASUMS256.txt.asc)

六、MD5 密码安全性

6.1 MD5 密文反向查询

前面我们已经提到通过对用户密码进行 MD5 运算可以提高系统的安全性。但实际上,这样的安全性还是不高。为什么呢?因为只要输入相同就会产生相同的输出。接下来我们来举一个示例,字符串 123456789 是一个很常用的密码,它经过 MD5 运算后会生成一个对应的哈希值:

MD5("123456789") -> 25f9e794323b453885f5181f1b624d0b

由于输入相同就会产生相同的结果,因此攻击者就可以根据哈希结果反推输入。其中一种常见的破解方式就是使用彩虹表。 彩虹表是一个用于加密散列函数逆运算的预先计算好的表,常用于破解加密过的密码散列。 查找表常常用于包含有限字符固定长度纯文本密码的加密。 这是以空间换时间的典型实践,在每一次尝试都计算的暴力破解中使用更少的计算能力和更多的储存空间,但却比简单的每个输入一条散列的翻查表使用更少的储存空间和更多的计算性能。

目前网上某些站点,比如 cmd5.com 已经为我们提供了 MD5 密文的反向查询服务,我们以 MD5("123456789") 生成的结果,做个简单的验证,具体如下图所示:

一文读懂 MD5 算法

 

因为 123456789 是很常见的密码,因此该网站能够反向得出正确结果那就不足为奇了。以下是 cmd5 网站的站点说明,大家可以参考一下,感兴趣的小伙伴可以亲自验证一下。

本站针对 md5、sha1 等全球通用公开的加密算法进行反向查询,通过穷举字符组合的方式,创建了明文密文对应查询数据库,创建的记录约 90 万亿条,占用硬盘超过 500 TB,查询成功率 95% 以上,很多复杂密文只有本站才可查询。已稳定运行十余年,国内外享有盛誉。

现在我们已经知道如果用户的密码相同 MD5 的值就会一样,通过一些 MD5 密文的反向查询网站,密码大概率会被解析出来,这样使用相同密码的用户就会收到影响。那么该问题如何解决呢?答案是密码加盐。

6.2 密码加盐

盐(Salt),在密码学中,是指在散列之前将散列内容(例如:密码)的任意固定位置插入特定的字符串。这个在散列中加入字符串的方式称为 “加盐”。其作用是让加盐后的散列结果和没有加盐的结果不相同,在不同的应用情景中,这个处理可以增加额外的安全性。

在大部分情况,盐是不需要保密的。盐可以是随机产生的字符串,其插入的位置可以也是随意而定。如果这个散列结果在将来需要进行验证(例如:验证用户输入的密码),则需要将已使用的盐记录下来。为了便于理解,我们来举个简单的示例。

Node.js MD5 加盐示例

const crypto = require("crypto");function cryptPwd(password, salt) {  const saltPassword = password + ":" + salt;  console.log("原始密码:%s", password);  console.log("加盐后的密码:%s", saltPassword);  const md5 = crypto.createHash("md5");  const result = md5.update(saltPassword).digest("hex");  console.log("加盐密码的md5值:%s", result);}cryptPwd("123456789","exe");cryptPwd("123456789","eft");

以上示例代码正常运行后,在控制台中会输出以下结果:

原始密码:123456789加盐后的密码:123456789:exe加盐密码的md5值:3328003d9f786897e0749f349af490ca原始密码:123456789加盐后的密码:123456789:eft加盐密码的md5值:3c45dd21ba03e8216d56dce8fe5ebabf

通过观察以上结果,我们发现原始密码一致,但使用的盐值不一样,最终生成的 MD5 哈希值差异也比较大。此外为了提高破解的难度,我们可以随机生成盐值并且提高盐值的长度。

6.3 bcrypt

哈希加盐的方式确实能够增加攻击者的成本,但是今天来看还远远不够,我们需要一种更加安全的方式来存储用户的密码,这也就是今天被广泛使用的 bcrypt 。

bcrypt 是一个由 Niels Provos 以及 David Mazières 根据 Blowfish 加密算法所设计的密码散列函数,于 1999 年在 USENIX 中展示。 bcrypt 这一算法就是为哈希密码而专门设计的,所以它是一个执行相对较慢的算法,这也就能够减少攻击者每秒能够处理的密码数量,从而避免攻击者的字典攻击。 实现中 bcrypt 会使用一个加盐的流程以防御彩虹表攻击,同时 bcrypt 还是适应性函数,它可以借由增加迭代之次数来抵御日益增进的电脑运算能力透过暴力法破解。

由 bcrypt 加密的文件可在所有支持的操作系统和处理器上进行转移。它的口令必须是 8 至 56 个字符,并将在内部被转化为 448 位的密钥。然而,所提供的所有字符都具有十分重要的意义。密码越强大,您的数据就越安全。

下面我们以 Node.js 平台的 bcryptjs 为例,介绍一下如何使用 bcrypt 算法来处理用户密码。首先我们需要先安装 bcryptjs :

$ npm install bcryptjs --save

Node.js bcryptjs 处理密码

const bcrypt = require("bcryptjs");const password = "123456789";const saltRounds = 10;async function bcryptHash(str, saltRounds) {  let hashedResult;  try {    const salt = await bcrypt.genSalt(saltRounds);    hashedResult = await bcrypt.hash(str, salt);  } catch (error) {    throw error;  }  return hashedResult;}bcryptHash(password, saltRounds).then(console.log);

以上示例代码正常运行后,在控制台中会输出以下结果:

$2a$10$O1SrEy3KsgN0NQdQjaSU6OxjxDo0jf.j/e2goSwSEu4esz9i58dRm

很明显密码 123456789 经过 bcrypt 的哈希运算后,得到了一串读不懂的 “乱码”。这里我们已经完成第一步,即用户登录密码的加密。下一步我们要实现登录密码的比对,即要保证用户输入正确的密码后,能正常登录系统。

Node.js bcryptjs 密码校验

async function bcryptCompare(str, hashed) {  let isMatch;  try {    isMatc = await bcrypt.compare(str, hashed);  } catch (error) {    throw error;  }  return isMatch;}bcryptCompare(  "123456789",  "$2a$10$O1SrEy3KsgN0NQdQjaSU6OxjxDo0jf.j/e2goSwSEu4esz9i58dRm").then(console.log);bcryptCompare(  "123456",  "$2a$10$O1SrEy3KsgN0NQdQjaSU6OxjxDo0jf.j/e2goSwSEu4esz9i58dRm").then(console.log);

以上示例代码正常运行后,在控制台中会输出以下结果:

truefalse

因为我们的原始密码是 123456789 ,很明显与 123456 并不匹配,所以会输出以上的匹配结果。

七、总结

本文首先介绍了消息摘要算法、MD5 算法的相关概念和特点,然后详细介绍了 MD5 算法的用途和 Java 和 Node.js 平台的使用示例,最后我们还分析了 MD5 算法存在的缺陷和 MD5 密码的安全性问题。这里大家需要注意,由于 MD5 碰撞很容易构造,基于 MD5 来验证数据完整性已不可靠,考虑到近期谷歌已成功构造了 SHA-1(英语:Secure Hash Algorithm 1,中文名:安全散列算法1)的碰撞实例,对于数据完整性,应使用 SHA256 或更强的算法代替。

除了文中介绍的 MD5 应用场景,MD5 还可以用于实现 CDN (Content Delivery Network,内容分发网络) 内容资源的防盗链,感兴趣的小伙伴可以阅读 深入了解 Token 防盗链 这篇文章。



Tags:MD5 算法   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
消息摘要算法是密码学算法中非常重要的一个分支,它通过对所有数据提取指纹信息以实现数据签名、数据完整性校验等功能,由于其不可逆性,有时候会被用做敏感信息的加密。消息摘要...【详细内容】
2020-02-25  Tags: MD5 算法  点击:(48)  评论:(0)  加入收藏
▌简易百科推荐
前言Kafka 中有很多延时操作,比如对于耗时的网络请求(比如 Produce 是等待 ISR 副本复制成功)会被封装成 DelayOperation 进行延迟处理操作,防止阻塞 Kafka请求处理线程。Kafka...【详细内容】
2021-12-27  Java技术那些事    Tags:时间轮   点击:(1)  评论:(0)  加入收藏
博雯 发自 凹非寺量子位 报道 | 公众号 QbitAI在炼丹过程中,为了减少训练所需资源,MLer有时会将大型复杂的大模型“蒸馏”为较小的模型,同时还要保证与压缩前相当的结果。这就...【详细内容】
2021-12-24  量子位    Tags:蒸馏法   点击:(11)  评论:(0)  加入收藏
分稀疏重建和稠密重建两类:稀疏重建:使用RGB相机SLAMOrb-slam,Orb-slam2,orb-slam3:工程地址在: http://webdiis.unizar.es/~raulmur/orbslam/ DSO(Direct Sparse Odometry)因为...【详细内容】
2021-12-23  老师明明可以靠颜值    Tags:算法   点击:(7)  评论:(0)  加入收藏
1. 基本概念希尔排序又叫递减增量排序算法,它是在直接插入排序算法的基础上进行改进而来的,综合来说它的效率肯定是要高于直接插入排序算法的;希尔排序是一种不稳定的排序算法...【详细内容】
2021-12-22  青石野草    Tags:希尔排序   点击:(6)  评论:(0)  加入收藏
ROP是一种技巧,我们对execve函数进行拼凑来进行system /bin/sh。栈迁移的特征是溢出0x10个字符,在本次getshell中,还碰到了如何利用printf函数来进行canary的泄露。ROP+栈迁移...【详细内容】
2021-12-15  星云博创    Tags:栈迁移   点击:(22)  评论:(0)  加入收藏
一、什么是冒泡排序1.1、文字描述冒泡排序是一种简单的排序算法。它重复地走访要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地...【详细内容】
2021-12-15    晓掌柜丶韶华  Tags:排序算法   点击:(16)  评论:(0)  加入收藏
在了解golang的map之前,我们需要了解哈希这个概念。哈希表,又称散列表(Hash table),是根据键(key)而直接访问在内存储存位置的数据结构。也就是说,它通过计算出一个键值的函数,将...【详细内容】
2021-12-07  一棵梧桐木    Tags:哈希表   点击:(14)  评论:(0)  加入收藏
前面文章在谈论分布式唯一ID生成的时候,有提到雪花算法,这一次,我们详细点讲解,只讲它。SnowFlake算法据国家大气研究中心的查尔斯&middot;奈特称,一般的雪花大约由10^19个水分子...【详细内容】
2021-11-17  小心程序猿QAQ    Tags:雪花算法   点击:(24)  评论:(0)  加入收藏
导读:在大数据时代,对复杂数据结构中的各数据项进行有效的排序和查找的能力非常重要,因为很多现代算法都需要用到它。在为数据恰当选择排序和查找策略时,需要根据数据的规模和类型进行判断。尽管不同策略最终得到的结果完...【详细内容】
2021-11-04  华章科技    Tags:排序算法   点击:(40)  评论:(0)  加入收藏
这是我在网上找的资源的一个总结,会先给出一个我看了觉得还行的关于算法的讲解,再配上实现的代码: Original author: Bill_Hoo Original Address: http://blog.sina.com.cn/s/bl...【详细内容】
2021-11-04  有AI野心的电工和码农    Tags: KMP算法   点击:(36)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条