grokking algorithm 第十一章 接下来要做什么呢?中文翻译

第十一章 接下来要做什么呢?
·············································································
在本章中
我会简要介绍10种在前面没有提到的算法,简单介绍下它们是否有用
根据你的兴趣,可以选择继续学习些什么
·············································································


让我们回到二分查找法的例子,当我们登陆Facebook时,它要去遍历一个大的数组来检查我们的用户名是否存在,我们说过,遍历数组最快的方式时二分查找法,但是有一个问题:每当有一个新用户注册时,你需要将它插入数组并对数组重新排序,因为二分查找法只能用于排序后的数组,若是你可以将新用户快速的插入正确的位置,是不是更好一些呢?
这里写图片描述
图11-1
这样你就不需要对数组进行重新排序了。这正是树形结构的想法。
一个二分查找树如下:
这里写图片描述
图11-2
对于每一个节点,左边的节点总是最小的,右边的节点总是最大的。
这里写图片描述
图11-3
假设你在查找Maggie,你从根节点开始。
这里写图片描述
图11-4

Maggie在David的后面,所以我们向右查找。
这里写图片描述
图11-5
Maggie在Manning的前面,所以我们向左查找。
这里写图片描述
图11-6
我们找到Maggie了,这和二分查找很像,在二分查找树中,时间复杂度一般是O(nlogn),最差的时间复杂度是O(n),查找有序数组,最坏情况的时间复杂度是O(logn),所以你可能觉得二分查找有序数组更好,但是二分查找数组插入和删除元素上,二分查找树在平均时间上更快。

这里写图片描述
图11-7
二分查找树有一些限制。第一,你不能随机取数,你不可以说,“给我树中的第5个数”,这需要花费的平均时间是O(logn),而且依赖树是平衡树,若是你的树形结构和下图相似。
这里写图片描述
图11-8
这棵树是倾斜树,这个树不会有好的性能,因为它是非平衡树。有一种特殊树可以平衡他们,例如:红黑树。
所以,二分查找树适用什么方案?B树,一种特殊的二分树,被普遍的用于数据库中。
若是你对数据库或者树形结构感兴趣,可以查看:
B树
红黑树

伸展树
倒排索引
这里有一个简化版的查找引擎工作的版本。假设你有3个有着非常简单内容的网页。
这里写图片描述
图11-9
让我们创建一个Hash表,Key值存储单词,value值存储单词在哪个页面出现。假设一个用户搜索单词Hi,我们看下哪个页面出现了hi?
这里写图片描述
图11-10
这里写图片描述
图11-11
啊哈,A页面和B页面都出现了。我们把结果呈现给用户。假设用户搜索three,我们知道A页和C页出现了,很简单吧?这个数据结构非常有用。Hash表用来存储单词和它们出现的地方。这个数据结构叫做倒排索引。在搜索引擎中很有用。若是你对查找感兴趣,可以从这个开始。

傅立叶变换
傅立叶变换是非常稀有的算法之一:聪明优雅。有数百万的使用场景。最好的学习媒介是Better Explained(一个将数学介绍的通俗易懂的网站),傅立叶变换可以告诉你制作冰沙的原料,换句话说,给你一首歌,傅立叶变换可以将它拆成独立的音符。
这也证实了这种想法有很多的使用场景。比如,你可以将歌曲分解为旋律,然后找出你关注的。你可以低音增强和隐藏高音。傅立叶变换很适合处理信号,也可以利用它来压缩歌曲。首先,将音频文件分解成音符,傅立叶变换可以很精确的告诉你多少音符组成了整首歌,你可以将不重要的音符去掉,这正是MP3格式是如何工作的。音乐不是唯一的数字信号,JPG格式是另一种压缩格式,它也是这么工作的。人们可以利用傅立叶变换来预测地震和分析DNA。
你可以利用它来制作类似Shazam的app,它可以猜测正在播放的是哪一首歌。傅立叶变换有很多种用途,你若是钻研,会发现更多。

并行算法
下面的三个主题是有关可量测性的,可作用于大数据。现如今,计算机运行越来越快,若是你想让算法快一点,你可能等几个月计算机本身就会快很多,但是我们处在世纪末了,笔记本和台式机的cpu有很多核,若是让算法快一点,我们可以使它们运行在多个核上。
例如,这是个简单的例子。排序算法是最快的,时间复杂度是O(nlogn),大家都知道,你不能在O(n)的时间内,对数组排序的—若你不用并行算法的话,用并行算法的快拍算法将数组排好序需要O(n).
并行算法很难设计,而且很难保证它们正确运行,运行时间能快多少页很难计量。有一点是确定的—时间节省并不是线性的,若是你的笔记本有2个核而不是单核,这并不意味着你的算法运行会比单核快一倍,这有很多原因。
管理并行性的开销。 假设有一个数组,有1000个元素需要排序,你怎么将这项工作分为2个核?每个分500个,然后将2个排好序的数组合并成一个大数组?合并2个数组也需要时间。
负载均衡—假设你有10项任务,你给每个核分配了5个任务。但是A核分到的都是简单的任务,所以10秒钟就完成了,但是B核分配到的任务都是很难的任务,它花费了1分钟,也就是说,当B核在工作时,A核空闲了50秒,你怎样分发工作,才能让每个核的工作任务都一样呢?

MapReduce
这是个并行算法而且它变得越来越流行了:分发算法。若是你的笔记本电脑有2个核或4个核,用并行算法是可以的,但是若是你需要上千个核呢?这样你可以写一个可以在多个机器上运行的算法了。MapReduce算法是一个流行的并行算法。你可以通过开源工具Apache Hadoop来使用它。

为什么分发算法是有用的?
假设你有一个表含有一亿行或者万亿数据,你需要运行一个非常复杂的SQL查询方法。你不能用MySQL,因为超过亿级行后,MySql就崩溃了。但是你可以通过Hadoop的MapReduce。
或者假设你有一个job清单,上面有很多要运行的job,每个job需要10秒,你有大约100万这样类似的job。若是你用一台机器,需要花费数周,但是若是用100台机器的话,只需要几天就可以了。
当你有很多工作要做而且要求很快完成的时候,分发算法是有用的。MapReduce由2个简单的步骤组成:map功能和reduce功能。

map功能
map功能非常简单,它作用于一个数组,对其中的每项都运用同一个功能。比如,我们将数组中的每项都乘以2.
这里写图片描述
图11-12
数组2 [2,4,6,8,10]中的每项都是数组1中的每项翻倍得到的。对一项乘以2是非常快的,但是若是有一个功能需要运行很长的时间,比如这个伪代码。

>>> arr1 = # A list of URLs
>>>arr2 = map(download_pages, arr1)

你有一个网页列表,你需要下载每个页面,然后将他们存储到arr2.每个页面需要好几秒。若你有1000多个URL,这需要好几个小时。
若你有100台机器,map可能将工作都自动的分发给他们,是不是很棒?你可以一次下载100个页面,这项工作就会快很多。这就是map当初的想法。
Reduce功能

一些人有时对reduce很迷惑,这个想法是你将很多项合并成一项。通过Map,你将一个数组分成了很多项。
这里写图片描述

图11-13
通过reduce,你可以将数组合并成一项。
这里写图片描述

图11-14
这是个例子

>>> arr1 = [1, 2, 3, 4, 5]
>>> reduce(lambda x,y: x+y, arr1)
15

在这个例子中,你可以将这些项加起来,我不会详细地解释reduce的功能,因为网上有很多专业的介绍。
MapReduce通过这两个简单的内容,可以运行在多个机器砂锅查询数据。当你有一个大型数据集(数亿行),MapReduce几分钟内就能给你答案,传统数据库需要几个小时。

布隆过滤器和HyperLogLog(基数统计)
假设你正在使用Reddit(一个社交新闻网站),当某个人上传一个链接时,你需要判断他以前是否上传过,没有上传过的内容被视为有价值的。所以你需要识别出这个链接是否被上传过了。或者假设你在用谷歌,你正在爬出网页,你只想爬取没有爬去过的网页,所以你需要识别出这些页面以前是否被爬取过。
或者你在使用bit.ly,它可以使URL变短。你不想重定向用户到恶意网站,你有一个恶意网站集合,现在你需要判断这个URL是否在恶意网站集合里面。
这些例子有一个共同点,那就是有一个非常大的集合。
这里写图片描述

图11-15
现在你有一些新的项,你需要判断它们是否在集合中。你可以使用Hash表来快速的得到答案。假设谷歌有一个很大的Hash表,里面的key值存储的时它爬去过的网页。
这里写图片描述

图11-16
你想看看是否爬取过adit.io,你可以在这个Hash表中查找一下。
adit.io —-> YES
adit.io在里面可以查到。你已经爬取过了,这个平均查询时间时O(1),adit.io在Hash表中,你爬取过了,花费的时间是常数时间,非常棒!
但是这个Hash表非常大,谷歌索引有10万亿个网页。若是谷歌给这些URL都建个索引,也需要占用很多的空间。Reddit和bit.ly网站有同样的问题(百度也有),若你有那么多的数据,你就需要创造性的获取结果了。

布隆过滤器
布隆过滤器提供了一个解决方案,这是一个概率数据结构。他给你的答案对的可能性比较大,但也有可能是错误的。除了Hash表,你也可以使用布隆过滤器来判断是否爬取过URL网页。Hash表可以给你一个精确的答案。但是布隆过滤器可以给你一个准确性很高的答案:
假阳性是可能的 谷歌可能会说,“你已经爬取过这个网页了”,实际上你并没有爬取过
假阴性是不可能的。若布隆过滤器说,“你没有爬取过这个页面”,那你肯定没有爬取过
布隆过滤器很伟大,因为它占用很小的空间。Hash表需要将每个爬取过的页面都存储下来,但是布隆过滤器并不需要。它们之所以伟大是因为在这些例子中,我们不需要精确答案。bit.ly可以说,“这个网站可能是恶意网站,你要小心!”

HyperLogLog算法
另一个类似的算法是HyperLogLog算法,假设谷歌要统计用户做了多少次不同的搜索,或者亚马逊要统计今天被所有用户访问过的额所有商品。查找这类问题的答案也很占空间。对于Google,它需要记录每一条搜索。当用户搜索什么时,它需要查询这个在日志中有记录了吗,若是没有,需要将它记录在日志中,尽管只是一天的数据,那日志的量也是非常巨大的。
HyperLogLog预测集合中的每项的值,和布隆过滤器很像。它不会给你一个准确的数值,但是答案是非常接近的而且使用的内存空间比起计算精确答案要少很多。
若你有很多数据而且也接受近似值,那么你可以试一下概率算法。

SHA算法
你还记得第五章中的Hash 表吗?我们复习一下,你有一个key值,你需要将相关的值写入数组中。

这里写图片描述
图11-17

你利用Hash功能来告诉你将值放入数组中的哪个位置。
这里写图片描述

图11-18

然后你将它的值放入数组中对应的位置。
这里写图片描述

图11-19
当查找时,花费的是常数的时间。当你通过值查找健时,花费的时间是O(1).
在这个例子中,你利用Hash功能将值区分出来,因此Hash功能输入一个字符串,然后将该字符串对应的值返回给你。

比较文本
另一个Hash功能是安全Hash算法功能,给定一个字符串,SHA算法会给你另一个字符串。
“hello”. ———->2cf24db…
术语有点绕,SHA是一个Hash功能,它产生一个Hash表,是另一个字符串。Hash功能将字符串转变成数组索引,SHA将字符串转换成字符串。
“hello” ————> 2cf24db…
“algorithm”. ———>b1ebb2ec…
“password” ————> 5e88489…
注意
SHA Hash表很长,我们只是简单介绍下
你可以利用SHA算法来判断两个文件是否相同。当你有很大的文件时,这非常有用。你想检查下朋友的大文件和你的是否相同,你不需要将你的大文件用Email发给他。相反,你可以计算这两个文件的SHA Hash值,并比较值的大小。当值相等时,它们是同一个文件,否则,则不是。
这里写图片描述

图11-20
校验密码
当你想校验字符串并且想隐藏原来的字符串时,SHA是非常有用的例子。假设Gmail被黑客攻击了,黑客偷了所有的秘密。你的密码被泄漏了吗?不!Google存储的不是原始的密码,存储的是经过SHA算法转换的密码。当你输入密码时,Google将它用Hash算法处理下,然后和数据库中存储的Hash值进行比较。

这里写图片描述
图11-21
所以它只是比较Hash值—它不需要你的密码!SHA算法被这样用作处理密码是很常规的。这是个单向散列,你可以得到这个字符串经Hash转换后的值。
abc123———> 6ca13d

但是你不能通过这个Hash值得到原来字符串的值
?<————- 6ca13d
这也就意味着若黑客得到了Gmail的经过SHA算法转换后的值,它不能将它们解析成原来的密码,你可以将密码转换成Hash值,但是反过来是不可以的。
SHA加密算法是一个算法家族:SHA-0,SHA-1,SHA-2和SHA-3.写这篇文章的时候,SHA-0和SHA-1被爆出有很多漏洞。你若是用SHA算法做密码加密,最好使用SHA-2或SHA-3.现在被公认为最安全的密码加密算法是bcrypt(尽管没有一种是万无一失的)

局部敏感哈希
SHA还有另一个重要的特征:它是局部敏感的。假设你有一个字符串,你为它生成了一个Hash值。
dog——-> cd6357
当你改变了这个字符串中的字符,然后重新生成Hash值时,这完全不同,
dot. ——-> e392da
这点非常好,因为黑客在破解密码时就不能靠比较两个Hash值的相似来判断密码是否相似。
有时,你想要相反的功能:你想要一个局部敏感哈希功能。这正是文档去重塑烦啊。当你对一个字符串做了小的改变时,文档去重算法生成的Hash字符串和原来的只有很小的不同。这样我们就可以比较两个Hash值到底有哪些不同了。这是非常有用的。
当Google爬取网页时,用文档去重算法可以检测是否是盗版
老师可以利用文档去重算法来检查学生上传的散文是否是抄袭的。
Scribd网站允许用户上传分享文档或书籍。但是她3不想让用户上传版权内容。网站可以利用文档去重算法来校验上传的《哈利·波特》是否和网上已有的是相似的,若是的话,自动拒绝。

当你要校验相似项时,文档去重算法非常有用。

Diffie-Hellman算法(密钥交换协议算法)
我们提到Diffie-Hellman算法,是因为它优雅的解决了一个古老的问题。你怎样来加密消息使它只能被真正接收的人读取呢?
最简单的方式是设置一个密码,比如a=1,b=2等等,如果你传送的是“4,15,7”,那么翻译过来就是“d,o,g”,但是我们必须都同一个这个密码才行,我们不能通过Email沟通,因为黑客有可能破解了我们的消息。真见鬼,就算我们面对面商议密码,有些人也有可能猜到它—因为它并不复杂。所以,我们是需要每天改变它。但是我们做不到两人每天见面,然后交换密码。
就算我们每天更换密码,这样简单的加密算法也很容易被破译,比如通过暴力算法。
如我看到一个消息“9,16,13,13,16,24,16,19,13,5”,我可以猜测a=1,b=2等等。
这里写图片描述

图11-22
这是令人费解的,可以试试a=2,b=3等等。
这里写图片描述
图11-23
这样起作用了。一个简单的类似这种加密很容易被破解。德国人用了一个非常复杂的加密算法—WWII。但是还是被破译了。Diffie-Hellman算法解决了2个问题。
两方不需要相互知道密钥。因此我们不需要见面,也不需要商议密钥。
加密算法很难被破解
Diffie-Hellman有两个密钥。公钥和私钥。公钥是公开的,你可以上传到网上或者通过Email发送,用你喜欢的哪一种方式都可以,不需要公开。当谁想要发送消息时,可以通过公钥加密消息但是只能通过私钥解密消息,因为私钥只有你有,因此只有你可以解密消息。
Diffie-Hellman依然在实践中使用,比如RSA算法。若你对加密算法感兴趣,你可以从Diffie-Hellman算法开始,它很优雅而且也不难接受。

线性规划
我把最好的放在最后,线性规划是我认为的几个最酷的事情之一。线性规划是在给定限制下获得最优解。例如,你的公司生产两种产品—衬衣和手提袋,需要1米布料和5个扣子,手提袋需要2米布料和2个扣子。你有11米布料和20个扣子。每个衬衣可以卖2美元,手提袋卖3美元。你需要做多少个衬衣和手提袋才能使收益最大呢?
另一个例子。你是一个政客。你想拉选票,调查发现(市场、研究等等),为了获取一个圣弗朗西斯科选民的投票,你需要花费1.5个小时,但是对于芝加哥选民来说,只需要花费1个小时,你至少需要500个圣弗朗西斯科选民支持,300个芝加哥选民的支持,你只有50天,一个圣弗朗西斯科选民花费2美元,芝加哥选民花费1美元,你的竞选资金是1500美元。你能最多得到多少选民的投票(圣弗朗西斯科+芝加哥)?
这里,你需要最大化选票,你的资金和时间是有限的。
你可能会在想,你讨论的都是求最优解的话题,这与线性规划有什么关系?这些图的算法通过线性规划也可以解决,线性规划是一个通用框架。图的问题只是其中的一个子集,我想你被打击到了。
线性规划使用了单纯形算法。这是个复杂算法,这也是为什么我不放在本书的原因。你若是对最优解感兴趣,可以查看线性规划。

结尾
我希望对这10个算法的简介让你对算法由更了解了些。我觉得最好的学习方法是找到感兴趣的地方,然后深入学习,这本书只是一本打基础的书。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值