热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

算法和数据结构初级|第三课:算法复杂度(上)

程序数据结构+算法作者谢恩铭转载请注明出处公众号「程序员联盟」(微信号:ProgrammerLeague)原文:https:www.jianshu.comp14982c42b2d8
程序 = 数据结构 + 算法

作者 谢恩铭 转载请注明出处
公众号「程序员联盟」(微信号:ProgrammerLeague )
原文:https://www.songma.com/p/14982c42b2d8

内容简介


  1. 算法的正确性
  2. 算法的复杂度
  3. “渐近”度量
  4. 第四课预报

1. 算法的正确性


上一课 算法和数据结构-初级 | 第二课:小鸭子们去旅行 中,我们讲了一个有趣的小故事,就是为了引出算法复杂度。

算法复杂度非常重要,要讲的内容也很多,所以我们分为上下两课


当程序员需要处理计算机科学相关的问题时,他们(通常)会编写一个程序。这个程序包含一个实现,也就是说需要把算法使用一种编程语言来实现。

我们知道,算法只是对处理问题的步骤的一种准确形容,它并不依赖于程序员所使用的编程语言或者工作环境。

我们在 算法和数据结构-初级 | 第一课:什么是算法和数据结构 里详情了一个“煮方便面”的食谱,这份食谱尽管简单,但可以说是一个算法。

我们是使用中文来形容这份食谱的,假如我现在把这份食谱翻译成一门外语(比方 英语),但食谱的内容还是不变,只不过换了一种语言来说明罢了。换个英国人来照着这份英文食谱煮方便面,跟我做出来的会是一样的。

那么,当程序员需要把算法使用一种编程语言来实现时,需要做什么呢?

像农夫 Oscar 一样,他必需首先验证他的算法是正确的,也就是说它产生了预期的结果,处理了所涉及的问题。这非常重要(假如算法不正确,那我们根本没有选择和优化它的必要),有时验证算法正确性是非常难的一步。

算法的正确性,英语是 Algorithm Correctness。要证实算法的正确性,有许多方法,我们本课程就不详述了,由于这不是我们的重点。大家有兴趣可以去网上搜索一下。

当然了,算法正确了,并不能保证明现这个算法的程序就没有错误(bug):
一旦我们有一个正确的算法,我们使用编程语言去实现它(通过编写一个执行它的程序)。但我们可能会写出有很多小错误的程序,这些小错误也许和所用的编程语言有关,它们可能在编写程序的过程中被引入。由于算法中一般不会形容如何管理程序的内存,或者者如何检查段错误(Segmentation Fault),等等,但这些都是程序员实现算法时需要考虑的问题。

2. 算法的复杂度


一旦程序员确信他的算法是正确的,他将尝试评估其效率,比方他会想知道“这个算法快不快”。

有人可能会认为,要知道算法快不快的最佳方式是实现该算法并在电脑上进行测试。

有趣的是,通常情况并非如此。例如,假如两个程序员实现了两种不同的算法,并在各自的电脑上测试程序运行的快慢。那么拥有更快速度的电脑的那个程序员可能会错误地认为他的算法更快,但其实并不肯定。

而且,要实现一个算法并测试,有时候并不容易。且不说有时候根据一个算法要写出代码很难,假如要实现的算法涉及到一枚火箭的发射,难道每次使用一枚真的火箭来发射一下去测试算法快不快吗?我们又不像钢铁侠那么有钱可以任性。

钢铁侠

出于这些起因,计算机科学家们发明了一个非常方便而强大的概念,也就是我们接下来要学习的:算法的复杂度。

“复杂度”(Complexity)这个词有点误导人,由于我们这里不是强调“了解起来有困难”(很复杂,很难),而是指效率 。

“复杂度”并不意味着“复杂的程度”。有的算法了解起来很难(很复杂),它的复杂度却可以非常低。

假如我给我的程序一个大小为 N 的输入,那么它将执行的操作的数目的数量级是 N 的一个怎样样的函数(f(N))呢?

算法的复杂度基于以下事实:处理问题的程序也取决于问题的条件:假如条件改变,程序执行的时间也会变长或者变短。

复杂度可以量化(通过数学公式)起始条件与算法执行的时间之间的关系。

为了“计算操作的数目”,我们必需首先定义什么是操作。对于这个问题,即便是绝顶聪明的科学家可能也无法非常明确地答复。由于选择哪些操作来做计算取决于所考虑的问题(甚至是算法)。

我们必需选择算法经常执行的少量操作,并且将其作为度量算法复杂度的基准。

例如,要制作煎鸡蛋,可以考虑三种基本操作:打破鸡蛋、铲碎正在煎的鸡蛋、煎熟鸡蛋。因而,我们可以计算每份煎鸡蛋的菜谱中的鸡蛋数目,从而理解菜谱(算法)的复杂度(煎鸡蛋是一个众所周知的菜,我们可以预期所有煎鸡蛋的菜谱都具备相同的复杂度:对于 N 个鸡蛋,我们进行 3N 个操作):增加盐、葱、胡椒或者其余佐料的操作非常快,不需要考虑在菜谱(算法)复杂度之内。

煎鸡蛋

又例如,在上一课农夫 Oscar 的情况下,装小鸭子的大箱子是 N 行 N 列,那么假如 Oscar 采取第一种旧的算法,他须要在池塘和卡车之间进行 N2(N 的平方)趟来回;假如使用第二种新的算法,他却只须要 N 趟来回。

这是复杂度的一种很好的度量方式,由于农夫 Oscar 在池塘和卡车之间来回这个过程是算法的所有操作里其耗时最长的。其余少量操作相对来说不那么耗时,比方 Oscar 从大箱子里挑出一只小鸭子,讯问小鸭子要去哪个池塘,等等。

因而,我们可以说,此算法的总时间几乎主要花在池塘和卡车之间来回这个操作上了,所以它可以作为度量此算法的效率的标准。

假如复杂度的概念对你来说还是有点模糊,请不要担心,之后的实践应该会让你豁然开朗。

3. “渐近”度量


我们可以说:复杂度是算法的渐近行为的度量

那么,这个比较复杂的词“渐近行为的度量”是什么意思呢?

这意味着“当输入变得非常大”(甚至“趋于无限”)时。这里的“输入”是算法的起始条件的一种量化。在农夫 Oscar 的情况下,这将意味着“当大箱子里有很多行/列小鸭子”时,例如 N 是 250。在计算机科学中,“很多”的含义却略有不同:例如搜索引擎会说“有很多网页”,1 万亿个网页...

“当输入变得非常大”(甚至“趋于无限”)时会有两种结果:

一方面,恒定的时间(常量,constant value)不予考虑。由于“恒定的时间”不依赖于输入。

例如,在农夫 Oscar 开始将小鸭子们带到每一个池塘去之前,他会先打开卡车的后车门。打开卡车后车门的时间被认为是“恒定的”:不管他的大箱子里有 20 行 20 列小鸭子还是有 50 行 50 列小鸭子,开后车门都是花费相同的时间。因为我们要考虑在大箱子的行/列的数目非常大的时候算法的效率,因而与 Oscar 在池塘和卡车之间来回的时间相比,打开卡车后车门的时间可以忽略不计。

另一方面,“常数乘法因子”也不予考虑:复杂度的度量不区分执行 N、2N 或者 250N 个操作的算法。为什么呢?我们考虑以下两种取决于 N 的算法:

第一种算法:

做 N 次(操作A)

第二种算法:

做 N 次(操作B 而后 操作C)

在第一种算法中,我们做 N 次 操作A;在第二种算法中我们做 N 次 操作B,N 次 操作C。假设这两种算法处理了同样的问题(所以都是正确的),并且所有操作都被考虑进复杂度的度量中:那么第一个算法做了 N 个操作,第二个算法做了 2N 个操作。

但我们可以说哪个算法更快吗?当然不行。由于这取决于 A、B、C 这 3 个操作所花费的时间:也行 操作B 和 操作C 都比 操作A 快 4 倍,那么总体来看,操作数为 2N 的算法比操作数为 N 的算法反而更快,由于 1/4 + 1/4 = 1/2(操作B 和 操作C 的耗时是 操作A 的四分之一)。

乘法因子不肯定对算法的效率具备影响,因而在复杂度的测量中不予考虑。

这也使我们能够答复一开始的那个问题:假如两个程序员有两台计算机,一台比另一台平均速度快 5 倍。5 这个常数乘法因子将被忽略,因而两位程序员可以毫无问题地比较算法的复杂度。

所以说,我们忽略了很多东西,这使得我们能有一个相当简单和普遍的概念。这种普遍性使复杂度成为一个有使用的工具,但它也有显著的缺点:在某些非常特殊的情况下,更复杂的算法居然可以使用更少的时间来完成(例如,常数因子在实际中也许能扮演非常关键的角色:假设农夫 Oscar 的卡车后车门卡住了,他竟花了一终日的时间来打开后车门)。

然而,在绝大多数情况下,复杂度仍是算法性能的可靠指标。特别是当两个复杂度之间的差距由于输入的增大而变得越来越大时。一个有 N 个比较耗时的操作的算法也许在 N 是 10 或者 20 的时候比另一个有 N2(N 的平方)个不那么耗时的操作的算法运行时间更长,但对于 N 是 2万 或者 N 是 5 百万的情况,复杂度更低的算法将一定是更快的。

4. 第四课预报


今天的课有点难度,不妨多读几遍。下一课我们继续研究算法的复杂度。一起加油吧!

下一课:算法和数据结构-初级 | 第四课:算法复杂度(下)


365 天,每天坚持写作之 3 / 365,爱上你的每一天!


我是 谢恩铭,在巴黎奋斗的软件工程师。
酷爱生活,喜欢游泳,略懂烹饪。
人生格言:「向着标杆直跑」


推荐阅读
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 一、Hadoop来历Hadoop的思想来源于Google在做搜索引擎的时候出现一个很大的问题就是这么多网页我如何才能以最快的速度来搜索到,由于这个问题Google发明 ... [详细]
  • 学习SLAM的女生,很酷
    本文介绍了学习SLAM的女生的故事,她们选择SLAM作为研究方向,面临各种学习挑战,但坚持不懈,最终获得成功。文章鼓励未来想走科研道路的女生勇敢追求自己的梦想,同时提到了一位正在英国攻读硕士学位的女生与SLAM结缘的经历。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 推荐系统遇上深度学习(十七)详解推荐系统中的常用评测指标
    原创:石晓文小小挖掘机2018-06-18笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值, ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • Ubuntu安装常用软件详细步骤
    目录1.GoogleChrome浏览器2.搜狗拼音输入法3.Pycharm4.Clion5.其他软件1.GoogleChrome浏览器通过直接下载安装GoogleChro ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • 2018年人工智能大数据的爆发,学Java还是Python?
    本文介绍了2018年人工智能大数据的爆发以及学习Java和Python的相关知识。在人工智能和大数据时代,Java和Python这两门编程语言都很优秀且火爆。选择学习哪门语言要根据个人兴趣爱好来决定。Python是一门拥有简洁语法的高级编程语言,容易上手。其特色之一是强制使用空白符作为语句缩进,使得新手可以快速上手。目前,Python在人工智能领域有着广泛的应用。如果对Java、Python或大数据感兴趣,欢迎加入qq群458345782。 ... [详细]
  • 阿里Treebased Deep Match(TDM) 学习笔记及技术发展回顾
    本文介绍了阿里Treebased Deep Match(TDM)的学习笔记,同时回顾了工业界技术发展的几代演进。从基于统计的启发式规则方法到基于内积模型的向量检索方法,再到引入复杂深度学习模型的下一代匹配技术。文章详细解释了基于统计的启发式规则方法和基于内积模型的向量检索方法的原理和应用,并介绍了TDM的背景和优势。最后,文章提到了向量距离和基于向量聚类的索引结构对于加速匹配效率的作用。本文对于理解TDM的学习过程和了解匹配技术的发展具有重要意义。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
author-avatar
赵_文赞
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有