第058封信 | 从计算机的算法,谈谈提高效率的本质

☆怦然*%心☆_☆动,你好!

我们昨天的内容算是一个铺垫,确立了评判计算机算法好坏的基础和标准。今天我们以计算机科学中最常见的算法——排序算法为例,说说提高效率的本质。

排序是我们在生活中经常会遇到的事情。在学校里老师会把一个年级的学生按照成绩排序,或者按照中学所在的地域排序;做电商的人,可能需要把所销售的各种商品按照收入或者交易量排序。排完序,我们有时就能看出很多规律,或者作进一步的处理了。比如,给学生排完序老师就可以评奖学金或者建议推研了,电商对销售根据一些选项排序后,就能改进自己的业务了。将现实世界的这些问题,变成计算机可以运行的程序,中间的桥梁就是排序算法。

计算机最早的排序算法源于人的生活和经验,这就如同最早的计算机下棋是模仿人,最早设计的飞行器是模仿鸟一样。那么我们人是怎么排序的呢?如果只有三五个数字,我们可以扫一眼就排完了序。但如果到几十个数字,这就有点麻烦了,因为如果没有一个必须严格遵守的流程,排完序经常会有些小错误。我在中学时还没有计算机,我们常常帮助老师统计同学们的期末考试成绩,发现把一个班上五十个人的成绩排序丝毫没有错误,并不容易。后来我们发现比较可靠的办法其实是下面两种笨办法:

方法一:第一次挑出成绩最高的同学,第二次挑出成绩次高的,如此重复,肯定能完成成绩的排序,一定不会错。

方法二:先将成绩单上第一个同学的名字和成绩写到旁边一张白纸的中央,如果第二个同学成绩比他高,就写到第一个同学的上方,如果比他低,就写到下方。等看到第三个同学的成绩后,根据他的成绩与前两个同学成绩的比较,插入到相应的位置。比如他的成绩正好在两个同学之间,就在旁边那张排序的纸上,把他的名字插入到前两个人之间。当然,那张排序的纸要留够空白,以方便插入后来同学的名字。

用这两种方法排50个人的成绩,工作量并不算小,比大家想象的大很多。是否有更好的排序方法,我和我高中的同学都没有想出来,其实也懒得想,因为我们所在的世界周围就那么些人,这两种笨办法够用了。

其实,早期的计算机科学家比我们也强不到哪里去,他们提出的排序算法就是上面两种。第一种算法被称为冒泡排序,因为每一次选出一个最好的,如同从水里冒出的气泡。第二种被称为插入排序,因为每一次要找到合适的位置插入。

接下来我们就用高德纳的思想,分析一下上述算法的复杂度。第一种算法很容易估算,50个人中找出最大的要比较49次,第二大的要比较48次,以此类推,大约是1200多次,是50的平方的一半左右。第二种算法的复杂度,也是和50的平方有关,这里就不再分析了。如果我们把50扩展到任意一个整数N,事实上使用上述排序的复杂度都是N平方左右。我们昨天讲到,在衡量计算机算法复杂度时,科学家们不关心几倍的差别,因此,在用数学公式表达复杂度的时候,高德纳干脆删除了前面的常数因子,只保留后面的变量,他用了微积分中的一个概念——大写的O的概念,所有同等复杂度的算法,都被认为它们在"大O的概念"下是相等的。比如,上述冒泡排序算法的复杂度是O(N平方),插入排序也是O(N平方),属于同一个量级。此外,早期的计算机科学家还想出了其他的排序算法,复杂度都和它们差不多,在一个量级。

接下来怎么提高计算机算法的效率呢?节省20%的计算量是没有意义的事情,就算省个三五倍也没有意义,要省就干脆多省一点,省它个成千上万倍甚至更多。于是,全世界所有的算法专家经过了十多年,终于发现从经验出发的排序速度慢的原因,就是做了无数的无用功。要提高效率,就需要让计算机少做事情。

以冒泡排序为例,之所以慢,是因为每一次选出一个最大的数,都要和其它所有的数字相比,其实并不需要这么麻烦,要想提高效率,就要减少数据之间的相互比较。最早对冒泡排序的改进是一种叫做归并排序的算法,它就利用了少做事情的思想,归并排序的思想大致如下:

首先,科学家们发现,如果我们把全班同学分成两组,分别排序,那么从每一组中挑选出一个最大的,就能省去一半的相互比较时间。于是他们就先将整个班级一分为二,先分别进行排序,再把两个排好序的组,合并成为一个有序的序列。相比排序,对有序的序列合并是很快的。归并排序这个词就是这么来的。这样做大约可以节省一半时间。当然,我们在前面也讲过,节省一半时间意义不大,但是别着急,因为对一个班级分出来的两个小组,排序时也可以采用上述技巧。

第二步,就是对两个组的排序。显然我们不应该再用冒泡排序。聪明一点的人马上会想到,既然能分成两组,就能把每个小组再分为两组,即分成四组,重复上面的算法,分别排序再合并。这样就能省3/4的时间。

再接下来,四组可以分为八组,能省7/8的时间,八组可以分为十六组,时间就不断省得越来越多。分到最后每个小组只剩下两个人的时候,其实就不用排序了,只要比较一次大小即可。

这种方法其实可以理解为两个过程,先是自顶向下细分,再自底向上合并。那么这种算法的复杂度等于多少呢?它相当于N乘以log(N),log(N)就是N的对数函数,大家不必在意N乘以log(N)是什么东西,只要记住它和N平方不一样,而且这个复杂度比前面的N平方小很多就行了。

为了便于你理解它小了多少,我们看看当N分别是100,1万,1百万,1亿时,两种算法的复杂度的情形:

第一种:即N平方,当N是100,1万,1百万,1亿时,它对应1万,1亿,1万亿,1亿亿。

第二种:即N乘以log(N),它对 应700,13万,2000万,23亿。

你可以看出N比较大了以后,N乘以log(N)比N平方要小很多,即23亿和1亿亿的差别,相差大约400万倍。400万是什么概念呢?大约是一支毛笔的长度和北京到上海距离的差别,或者是你和我两个人的重量和瓦良格号航空母舰重量的差别。

这样一对比,你就能感觉到为什么计算机的算法是如此重要。算法没有学好的人,写出来的程序经常是不合格的,因为很容易就浪费掉成千上万倍的计算机资源。大家不要觉得一个亿是什么了不得的大数字,且不说腾讯或者阿里巴巴这样公司的用户数早就超过了一个亿,即使你编写一款游戏,只要有人使用,几天下来的日志都有上亿行,对一亿个数排序,在计算机应用中是很常见的事情。

归并排序算法相比之前的算法为什么效率提高这么多?因为它少做了很多并不需要做的比较。很多人问我,你为什么效率这么高?并不是我效率高,而是做事情比大家少。效率=产出/所做的事情。人的产出是很难提高的,但是所做的事情是可以减少的。

我一直强调工程师水平差一级,贡献可能就差出10倍,有人不服气,说会差这么大么?从上面的一个例子大家可以看出,可能差得还不止十倍。很多人问,我想改行搞计算机,自己找两本书看看是否就可以了?我的答案是不可以,在今天这样一个人多粥少,人的技能普遍高出行业基本要求的时代,进入任何一个行业,都要有点专业精神,把自己当作科班出身来要求。在农耕文明时代,没有力气的人最不济也能产生壮劳力1/3的生产力。在工业时代,靠手工一件件生产商品,可能效率能有机器的1%。但是到了智能时代,本事差一点,效果可能差几百万倍,几亿倍,专业和不专业就差得更远了。

为什么到了智能时代学习变得非常重要了呢?因为一些基本的方法和道理如果不学习,靠自己脑子苦思冥想可能需要十年甚至更多的时间,而学习加练习,可能只要一个月的时间就够了。早期的计算机科学家因为受限于自己的生活环境,也想不出好的排序方法,今天比较常用的排序算法"快速排序(Quicksort)",是在计算机诞生后13年才出现的。这个算法,我下次花十分钟时间,就可以给大家讲清楚,大家可以自己判断,是应该学习,还是自己琢磨呢?

明天我们会谈谈快速排序,以及它背后的方法论。

今天的思考题是这样的:归并排序相比那些效率低的简单排序,其实还说明了一个道理,就是将一个复杂问题分解成很多简单的问题,一个个解决,最后比直接解决复杂问题要省很多时间。能否就这件事发表你的看法?

已读

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容

  • 一. 写在前面 要学习算法,“排序”是一个回避不了的重要话题,在分析完并查集算法和常用数据结构之后,今天我们终于可...
    Leesper阅读 2,520评论 0 40
  • 概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    蚁前阅读 5,164评论 0 52
  • ☆怦然*%心☆_☆动,你好! 昨天我们介绍了好的算法和坏的算法区别有多大。那么你可能会问,世界上已知的最好的算法是...
    怦然心_动阅读 424评论 0 0
  • 读这本书的目的是想了解此书讲的超级记忆,就是在速度阅读的基础上进行记忆,这是我所缺乏的,所以我非常想了解。 此书我...
    晏子266840阅读 131评论 0 0
  • 北京时间10月25日,方雅性格完善中心/中国智心委心理危机干预办公室国际学术交流之旅第五日赴全球最大的健康城——迪...
    方雅性格完善中心阅读 204评论 0 0