几个重要的算法概念

反向索引


一个散列表,将单词映射到包含它的页面。这种数据结构被称为 反向索引(inverted index),常用于创建搜索引擎。
这里非常简单地说说搜索引擎的工作原理。假设你有三个网页,内容如下。

在这里插入图片描述

我们根据这些内容创建一个散列表。 这个散列表的**键为单词**,**值** 为包含指定单词的**页面**。现在假设有用户搜索 `hi`,在这种情况下,搜索引擎需要检查哪些页面包含 `hi`。
单词页面
HIA, B
THEREA, C
ADITB
WEC
GOC

傅里叶变换


傅里叶变换有一个绝佳的比喻:给它一杯冰沙,它能告诉你其中包含哪些成分。换言之,给定一首歌曲,傅里叶变换能够将其中的各种频率分离出来.
这种理念虽然简单,应用却极其广泛。例如,如果能够将歌曲分解为不同的频率,就可强化你关心的部分,如强化低音并隐藏高音。傅里叶变换非常适合用于处理信号,可使用它来压缩音乐。为此,首先需要将音频文件分解为音符。傅里叶变换能够准确地指出各个音符对整个歌曲的贡献,让你能够将不重要的音符删除。这就是MP3格式的工作原理!傅里叶变换还被用来地震预测和DNA分析。


并行算法


我们身处一个处理器速度越来越快的时代,如果你要提高算法的速度,可等上几个月,届时计算机本身的速度就会更快。但这个时代已接近尾声,因此笔记本电脑和台式机转而采用多核处理器。为提高算法的速度,你需要让它们能够在多个内核中并行地执行!
并行算法设计起来很难,要确保它们能够正确地工作并实现期望的速度提升也很难。有一点是确定的,那就是速度的提升并非线性的,因此即便你的笔记本电脑装备了两个而不是一个内核,算法的速度也不可能提高一倍,其中的原因有两个。

  • 并行性管理开销。假设你要对一个包含 1000 1000 1000 个元素的数组进行排序,如何在两个内核之间分配这项任务呢?如果让每个内核对其中 500 500 500 个元素进行排序,再将两个排好序的数组合并成一个有序数组,那么合并也是需要时间的。
  • 负载均衡。假设你需要完成 10 10 10 个任务,因此你给每个内核都分配 5 5 5 个任务。但分配给内核 A 的任务都很容易, 10 10 10 秒钟就完成了,而分配给内核 B 的任务都很难, 1 1 1分钟才完成。这意味着有那么 50 50 50 秒,内核 B 在忙死忙活,而内核 A 却闲得很!你如何均匀地分配工作,让两个内核都一样忙呢?
    要改善性能和可扩展性,并行算法可能是不错的选择!

MapReduce


在并行算法只需两到四个内核时,完全可以在笔记本电脑上运行它,但如果需要数百个内核呢?在这种情况下,可让算法在多台计算机上运行。 MapReduce 是一种流行的 分布式算法,你可通过流行的开源工具Apache Hadoop来使用它。


分布式算法为何很有用


假设你有一个数据库表,包含数十亿乃至数万亿行,需要对其执行复杂的 SQL 查询。在这种情况下,你不能使用 MySQL,因为数据表的行数超过数十亿后,它处理起来将很吃力。相反,你需要通过 Hadoop 来使用 MapReduce。又假设你需要处理一个很长的清单,其中包含 100 100 100 万个职位,而每个职位处理起来需要 10 10 10 秒。如果使用一台计算机来处理,将耗时数月!如果使用 100 100 100 台计算机来处理,可能几天就能完工。

分布式算法非常适合用于在短时间内完成海量工作,其中的 MapReduce 基于两个简单的理念:映射(map)函数归并(reduce)函数


映射函数


映射函数很简单,它接受一个数组,并对其中的每个元素执行同样的处理。例如,下面的映射函数将数组的每个元素翻倍。

arr1 = [1, 2, 3, 4, 5]
arr2 = map(lambda x: 2 * x, arr1) # [2, 4, 6, 8, 10]

arr2 包含 [2, 4, 6, 8, 10]: 将数组 arr1 的每个元素都翻倍!将元素翻倍的速度非常快,但如果要执行的操作需要更长的时间呢?请看下面的伪代码:

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

在这个示例中,你有一个 URL 清单,需要下载每个 URL 指向的页面并将这些内容存储在数组 arr2 中。对于每个 URL,处理起来都可能需要几秒钟。如果总共有 1000 1000 1000URL,可能耗时几小时!
如果有 100 100 100 台计算机,而 map 能够自动将工作分配给这些计算机去完成就好了。这样就可同时下载 100 100 100 个页面,下载速度将快得多!这就是 MapReduce 中“映射” 基于的理念。


归并函数


归并函数可能令人迷惑,其理念是将很多项归并为一项。映射是将一个数组转换为另一个数组。

在这里插入图片描述
映射的作用

而归并是将一个数组转换为一个元素。

在这里插入图片描述
归并的作用

下面是一个示例:

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

在这个示例中,你将数组中的所有元素相加: 1 + 2 + 3 + 4 + 5 = 15 1 + 2 + 3 + 4 + 5 = 15 1+2+3+4+5=15
MapReduce 使用这两个简单概念在多台计算机上执行数据查询。数据集很大,包含数十亿行时,使用 MapReduce 只需几分钟就可获得查询结果,而传统数据库可能要耗费数小时。


布隆过滤器和HyperLogLog


布隆过滤器HyperLogLog 都是概率型选择算法
假设给定一个元素,你需要判断它是否包含在这个集合中,例如, Google 可能有一个庞大的散列表,其中的 是已搜集的网页。
散列表的平均查找时间为 O ( 1 ) O(1) O(1),只是 Googl e需要建立数万亿个网页的索引,因此这个散列表非常大,需要占用大量的存储空间。此时,可以使用 布隆过滤器 ,它可以给出一个近似的结果,也许这个结果不正确,布隆过滤器的优点在于占用的存储空间很少。
HyperLogLog 是一种类似于布隆过滤器的算法
如果 Google 要计算用户执行的不同搜索的数量,或者 Amazon 要计算当天用户浏览的不同商品的数量,要回答这些问题,需要耗用大量的空间!对 Google 来说,必须有一个日志,其中包含用户执行的不同搜索。有用户执行搜索时, Google 必须判断该搜索是否包含在日志中:如果答案是否定的,就必须将其加入到日志中。即便只记录一天的搜索,这种日志也大得不得了!
HyperLogLog 近似地计算集合中不同的元素数,与布隆过滤器一样,它不能给出准确的答案,但也八九不离十,而占用的内存空间却少得多。


SHA算法


散列表中,散列函数非常重要,我们通常希望 散列函数 的结果是均匀分布的。散列函数 接受一个字符串,并返回一个索引号。
常用的 散列函数安全散列函数(secure hash algorithm, SHA),其给定一个字符串的输入,生成另一个字符串的输出(SHA 生成的散列值很长)。通常用于 比较文件生成密码

在这里插入图片描述

假设你有一个$4$ GB的文件,并要检查朋友是否也有这个大型文件。你们只需要对两个文件的 SHA 散列值进行比较即可。

在这里插入图片描述

Google 保存的并非是用户的密码,而是由用户密码生成的 SHA 散列值,而且SHA并不支持由散列值逆推输入字符。这样即使 Gmail 遭到攻击,攻击者也无法获取用户的密码。
SHA 是一系列的算法:SHA-0、SHA-1、SHA-2、SHA-3。目前,SHA-0、SHA-1已被发现存在一些问题。SHA-2、SHA-3会更加安全。但是,安全只是暂时的。


局部敏感的散列算法


SHA 具有局部不敏感的特征,即两个字符串存在微小的不同,也会产生两个差别巨大的结果。例如: d o g → c d 6357 dog \rightarrow cd6357 dogcd6357 d o t → e 392 d a dot \rightarrow e392da dote392da
但是,有的时候我们希望散列函数具有 局部敏感 的特征。例如两个只有细微不同的输入字符串产生两个只有细微不同的散列值。Smibash 可以实现这样的效果。

  1. Google 使用 Simhash 来判断网页是否已搜集。
  2. 老师可以使用 Simhash 来判断学生的论文是否是从网上抄的。
  3. Scribd 允许用户上传文档或图书,以便与人分享,但不希望用户上传有版权的内容!这个网站可使用 Simhash 来检查上传的内容是否与小说《哈利·波特》类似,如果类似,就自动拒绝。

Deffie-Hellman密钥交换


Deffie-Hellman 解决了一个古老的加密问题:如何对信息加密,以便只有收件人看懂?
Deffie-Hellman 使用两个密钥:公钥和私钥。经过公钥加密的信息只有通过对应的私钥才能打开。公钥是可以向外发布的,而私钥是自己保存的。Deffie-Hellman 算法解决了如下两个问题:

  1. 双方无需知道加密算法,他们不必会面协商要使用的加密算法。
  2. 要破解加密的消息比登天还难。

参考资料


  1. 《算法新解》,有兴趣的同学可以看一下,讲得还是很不错得。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值