关于算法

不得不说,有时候无知是福,看到一点有趣而深入的东东,就能感受到神奇。越是咱们熟悉的东西,每每倒是咱们进一步理解深入的障碍,而之因此是障碍是咱们并不知道这个是咱们理解问题的障碍。困惑中的每一次豁然开朗每每是从一点一滴的咱们已经成为惯性思惟中开始。越是深入的原理,每每越是简单强大。就像爱因斯坦打破牛顿给咱们原有的世界观同样。对于一个打破常规,让你从新理解问题的最简单的方法就是把你整个思考的前提否认。而带来的结果就是咱们看问题的角度,层面有了更大的扩展。因此,有时候知道的太多反而不美,作一个白痴也很幸福。html

哎,又无病呻吟了半天。之因此有上述感想。还得感谢本身的同窗。因为我没有看过MIT的经典课程《算法导论》而被鄙视,并且更无语的是,个人理由是“听不懂,若是有老师的课堂发音的记录”,而事实上。这个MIT早就提供了,为了照顾想我这样的听力很差的家伙。好吧,我是个白痴,不过就像上面讲的,白痴也有白痴的幸福。这个假期,无聊的时候,不只能够看《爱情公寓2》也能够屡屡本身的数学常识了。:)面试

《算法导论》是一名研究算法设计的课程。设计算法,咱们关心的主要是2个方面,一个是性能,另外一个是资源花费。固然,咱们重点的是性能,咱们老是但愿咱们的程序跑的更快。那么学习算法到底有什么用呢?这是一个经典的问题。Charles Leiserson 是这样给咱们解答的。首先,列举了一大堆在实际编程中比性能更重要的东西:可维护性,模块化,功能,用户体验等等。特别是用户体验,那么既然有这么多的东东比算法重要,那么为何咱们还要学习算法呢?算法

  • 算法决定了可行仍是不可行。

在一些实时的状况下,好比机器人等嵌入式设备,咱们不够快,那么就没有意义,若是咱们用了太多的内存,一样不行。因此,算法这个东东,老是在咱们计算机领域的最前沿部分,如人工智能,搜索引擎,数据挖掘。若是咱们是在作10年前就已经实现了的东西,那么性能的确在一些状况下已经不重要了。可是,若是想作一些别人没有作过的东西,真正的实现从无到有的过程。那么其中遇到的绝大多数问题都是,数据太复杂了。没有能力在有限的资源下找到答案。这也就是为何叫计算机科学,而不是计算机工程。(固然科学这个和名字是无关的,好比物理,历来没有那个学校叫个什么物理科学什么的。:))。不得不说,MIT的目标是为世界培养leader,而咱们那破学校是为了培养farmer(这里并无不敬在里面,并且事实上,作一个farmer挺好的,每一年坐在家里,收个房租,年底村里再分个几十万,比那些城里白领好多了在物质上)。其实也不那么绝对,非要改变世界,只要是以前没有作过的程序,咱们在实现以前,首先思考的必定是算法。其次,则是对他不断的优化,完善。编程

对绝大多数的刚刚参加工做的同窗,每每不能体会到整个产品的建立过程。参与的仅仅是完善,算法的设计或是大致设计已经完成,因此感受不到算法的存在。而匆匆下了学校白学的定论。而随着工做时间变长,总会遇到没有或是不能直接利用原有设计的东东,那么算法也就体现出价值了。windows

  • 算法是一种描述程序行为的通用语言。

咱们能够经过算法去描述程序的运行流程,在任何地方。他不只能在实践中获得体现,也能在理论中获得证实。并且可以获得你们一致的见解。而这是别的永远没法作到的,好比用户体验,每一个人都有本身的想法,咱们不可能让全部人都满意咱们的设计,而算法却能够作到,由于快就是快。放到计算机上一跑结果自知。别人没法击败你,即使是再挑剔的对手,只要你足够出色。而可以知足这样条件的前提就是,算法是一个如此通常化,基础的东西。就像Charles Leiserson 所讲,算法就像钱,你能够用钱去买吃的,喝的。而衡量这些花费的就是钱的数目。在计算机上,则是,选择一个这样的策略,须要花费多少。选择另外一个策略,须要花费多少。而衡量这2个选择谁的花费多呢?是算法。设计模式

算法在计算机中的地位,就和数学在全部理科学科中的地位同样。我曾经问过个人数学老师一个问题,他的回答让我直到如今还记忆犹新。“老师,数学在您眼中是什么呢?”“数学是全部理科中是最奇妙的一个。由于他能够独立于其余任何学科存在而其余学科离开不了数学。”是的。可以想象物理化学离开数学以后是什么样子么?可是数学为何可以独立存在?是由于他构建了一门语言,一门伟大的语言。使用这门语言可让知识在任何领域中环绕,学好数学就好像有了一张无限透支的通用支票,能够在任何地方花费(黄金?)。做为一个可让这么多地方都通用的缘由中最重要的就是,他是超级稳定的。是一个说一是一的世界。一个公平的世界,绝对的世界(固然,如今数学这个概念也不许确了,这个充分体现了哲学思想,有正必有反啊:P)。他所肯定的东西的结果是确定的。没有歧义,并且不随时间变化而流动。好比,咱们真实世界中交流的语言,好比“忽悠”,“猥琐”。等等。不少词义,随着时间的变化而改变了。使得不少年纪大的人,和咱们这年轻人在交流上就产生了隔阂。而咱们最熟悉另外一个例子就是文言文,特别是其中的一些扭曲的字。但数学这种基础类学科是不会的。至少在一个能够预见的范围是稳定的,没有地域限制的。因此,数学才能站在人类科学发展的最前沿,他的每一次前进的一小步,都能改变世界。这就是数学之美。一样也是本身可以让绝大多数人接受的最大障碍。因为他改变的太慢,并且枯燥。绝大多数人没法深刻的理解。当用世俗,腐烂,充满铜臭,功利的眼光看待纯净的数学世界,必然发现数学无用。并且,这的确是事实,由于大部分人,都不可能成为改变世界的家伙(这里的确不许确,由于改变世界话题太大,修理地球一样也是改变世界。)。模块化

算法,一样为咱们计算机构建了一个纯净的世界。一个说一是一的世界,他所肯定的,没有可以反驳的。固然,就和学习数学同样,咱们不是去成为数学家,学习物理,不是去成为物理学家,而后去作哪些可以改变世界的东西。学习这些基础类学科的重要在于,他提供了一个让咱们和那些站在人类史上最顶尖的家伙们交流的语言,从个人角度来看。若是没学好数学,可以和牛顿,爱因斯坦交流么?没有学好算法,可以和高爷爷交流么?做为一个普通人,咱们只要学习到他们身上的一点点,也就足够了。固然,这不是对全部家伙都有效,有些人老是想,和那些老家伙有什么好交流的,给我一个周杰伦的签名吧。:)性能

  • 学习算法还有一个缘由,是的,就是兴趣。这个传说中最牛X的老师。

喜欢算法,没有别的缘由,是的。我就是喜欢比别人快速的感受。喜欢数学,是的。由于大部分人数学很差。因此我就喜欢数学。迎难而上,哥就是喜欢作别人作不了的东西。是的,虽然听上去很牵强,并且比较扭曲。比较符合印象中90后的想法。不知道90后是否是能产生更多的数学家呢?学习

让咱们回到咱们的算法上,既然咱们这么关注性能,那么什么是影响性能的因素呢?优化

对于一个计算机外行来讲,首先就是计算机硬件自己的运算能力。多一个超级牛的CPU,超大的内存,固态硬盘。确定运算快。的确,若是你拿一个超级计算机和地摊上买的一个小的计算器比运算能力。这个实在是一个很显然的结果。是的,因此,咱们有些状况下,须要思考在相同条件下,到底哪一个算法的性能更高。这比较的是相对速度。可是咱们却不能忘了这一点。有时,咱们想使用一些很通常的计算机,经过优秀的算法,来战胜那些拥有更高硬件的那些家伙们,而咱们则必须关心算法性能的绝对速度。那么咱们该如何描述这些看似互相矛盾的东西呢?不要忘记,算法但是基础啊,咱们要的是一个确切的答案。咱们如何给出一个确切的答案,而这个答案无论是超级计算机,仍是普通PC都可以支持呢?这就是算法中最重要的一个概念,甚至是一切分析的大前提,一个能够把这些复杂的因素都考虑在内(或是都不考虑在内)的东东转换为能够用数学分析的对象。这就是渐进分析。

渐进分析的基本思想是

  • 忽略硬件结构
  • 不使用真实世界的运行时间,而是关心运行时间的增加速度为对象

渐进分析是一个很是庞大的概念,咱们最熟悉的,也是大多数本科院校教咱们的就是Θ,O,Ω等等相似的这些符号。这里只从Θ开始。

对一个初学者,Θ-notation是比较容易接受的。对一个多项式,咱们只须要删除掉全部的低次幂项,忽略掉常数,系数这些次要因素。就和Charles Leiserson 所讲的。这个描述,是工程方向的描述,并非严格的数学上的定义。而对像我这样的小白来讲,最大的误解就是把他当成了数学上的严格定义而产生了极大的困惑。

image

这个是一个至关经典的图,当n趋于无穷大时,Θ(n3)总能干掉Θ(n2)。无论是一样的硬件设备,仍是不一样的硬件设备。只是在不一样的设备下,不一样的算法下,咱们有了一个不一样的系数,低次幂项,和常数。可是,咱们关心的是他随着数据输入长度的变大而产生的增速。当n超过n0时,任何的次要因素都是浮云了。咱们就能够说Θ(n3)被Θ(n2)干掉了,即便Θ(n3)的硬件要比Θ(n2)好不少,在一开始的时候效率有多高。

这是一个伟大,cool的概念。是的,他完美的既知足了咱们追求的绝对速度,也能知足咱们追求的相对速度。能够说,这给了咱们继续学习算法的动力。可是,事实上,在实际开发中,咱们有时候却使用那些在学校中认为是效率低的算法。难道这个理论错了?固然不是,错的是咱们,咱们忽略了一个很大的前提,n0。在咱们多数开发过程当中,不多接触那些海量数据的运算。咱们的运算多数是在一个较少的数据上下浮动,这个也能够说咱们的硬件,资金,产品,根本不须要咱们整那么大的数据。也就是n0,咱们根本达不到。事实上,只要是有脑子的,看到这个图,在小于n0的前提下,都会作成正确的判断。但对于刚刚步入IT的广大学生,却老是犯下屁股决定脑壳这样愚蠢的选择。而这其实,就是作科学和作工程师的最大区别。理论和实践相互掰手腕的结果。

这几天,挖老赵的“坟”,找出了这么一篇。写程序时该追求什么,什么是次要的?里面有一段十分搞笑的代码,之因此这样说,是由于我本身也写过这样的代码。想一想真是dt啊。回想事发现场,我记得是我看了个什么相似《面试宝典》东东,有一些题考察交换元素,事实上,你能够找到一大堆的,并且是更精妙的去交换2个元素。看到以后,如获至宝。只要是2个元素要换位置,就用。站在作科学的角度上看,这无可厚非。可是若是站在工程的角度来看。这就是明显的多此一举。每每花费80%的精力在提升%20的性能上,而不是去花费20%的精力提升80%的性能。这一样是刚刚步入IT的广大同窗的问题。作科学须要严谨,可是在工程方面,考虑的事情很是复杂,多。咱们必需要关注在核心,关键的部分。这样才能在有限的资源下,最大的作出东东来。实践中,没有任何项目的资源是足够的。MS,Google都会有资源不足的时候。咱们须要学会抓住重点。固然这里并无鄙视这些面试问题,事实上,这些问题的背后每每是考察数学思惟的基本功,而不是鼓励你们这么作。就像那个经典的问题,12个小球一架天平。没有仔细,严谨的思考,可以想到这个东东能和排序问题扯上勾么?神啊,万恶的功利,给完美的数学模型批了一层邪恶的外套,使咱们在追求本质的过程当中迷失。

有关n0的问题,不只在算法设计上,也出如今咱们的设计模式之中。《设计模式》这本神书,我是没看过,也不敢看。但也隐隐感受到相似“设计过分”的言论。这一样都是在理论和实践结合上出了问题。固然,很多理论支持者,确定会说,那是由于你没作过那么大的项目。但事实倒是,无论设计多么复杂的,仍是多么简单的,实践和理论永远不可能都获得知足。windows操做系统能够说是一个咱们可见的最大的项目之一了。可是windows也并非一个微内核,在内核中也绑定了很是多的“多余”的部分从理论上看。那无疑会下降系统稳定性,提升维护难度。可是咱们却不能不说windows是最成功的一套软件之一(这个之一甚至均可以去掉)。

固然,要想在作学问和实践找到平衡点。这个无疑是极大的挑战。只是分析理论,而不实践,那么永远不可能成为一个出色的工程师。除非你的目标是成为理论科学家。反过来,若是不理论而只是实践,不一样的是,这个是能够成为一个出色的工程师。因此,这里有一句经典的话。

If you want to be a good programmer, you just program ever day for two years, you will be an excellent programmer. If you want to be a world-class programmer, you can program every day for ten years, or you can program every day for two years and take an algorithms class.

既然算法是如此的重要,那么咱们该如何学呢?其实,这是一个很纠结的问题。甚至是一个鸡生蛋,蛋生鸡的问题。不学算法,你不会了解他,也不会认识到算法重要,反而。认为算法不重要,那么也就不会下功夫去学。这就又回到一开始的那个unknown unknown上了。因此,若是准备学习算法,也就意味着选择了一条坎坷的路。一开始特别迷茫,可是没有别的选择。惟有坚持,放下浮躁,功利的心态,沉浸在数学的世界中才能体会到数学的价值,数学的乐趣。也只有这样,才能坚持到最后。

固然,能作到这一点的,敢说体会到数学之美的家伙,全世界也没有几我的。那么做为一个普通人,咱们怎么才能最大的去提升本身,更好的掌握实践和科学的平衡点呢?这个问题,我本身也没有答案。由于我既没经验又没理论。这里只是扯下我本身的理解,可能很偏激。

首先应该研究下刘未鹏的不少博客内容,特别是锤子和钉子。对我这样的新手来讲,武器真的太少了。因此当捡到一个武器每每过于兴奋而忽视了这个武器的使用前提,每每杀鸡用牛刀,并且还达不到积极的效果。就是由于咱们拿到锤子以后,全部东西看上去都像钉子。因此,咱们惟有摆正心态,深刻了解拥有的武器,并增长更多的武器,见更多的市面,才能坐怀不乱,达到手中有锤,心中无锤的最终境界。

一个稍微实际的例子。对像我这样的菜鸟来说,大部分都会遇到这样一个问题。并且困惑好久好久。“堆排序为何比快速排序在大多数时要慢呢?”事实上,形成这个问题的主要缘由(对我)就是,没有理解明白Θ-notation。那些被忽略掉的次要因素,固然还有更重要的是数学上对几率的薄弱理解。而后咱们会再映射出一大堆的数学基础知识,而后大部分人死在沙滩上(真的,这是我从小以来最大的遗憾,就是没有学好几率,而形成这个的缘由竟然是,这些题目初学时每每是用平常用语出题,而因为本人语文太差,总不能理解清楚题意,而对这类题目产生了极大的抵触,可见小朋友们千万不要偏科:P)。从科学的角度去,彻底能够证实这个问题,可是付出的代价就是没有硕士以上的数学能力的玩家,没有机会理解到那个层次。那么,其实咱们能够从另外一个角度看,直接放到计算机上跑一下就能够了么。是的,我不是科学家,我只须要知道结果就OK了。是啊,好在咱们处在一个和谐的世界。让咱们从这个庞然大物中得以解脱,因此,有时,咱们须要根据自身状况,放弃一些东西,特别是那些比较可以经过实验来证实的东西。

好吧,总不能啥也放弃吧,都放弃了那到底也简单了。这里,我只能说,我推荐SGI STL。在我看来,这是一个结合了设计模式,理论算法与实践最好的一个实例。他不只是开源的,代码量也很少,命名也算规范,并且还有一本侯捷大师的著做来诠释,帮助咱们理解,并且还能帮助咱们具体实践过程当中规避一些错误。咱们每个在学校学习的算法,咱们均可以在这里找到答案(至少能够用来作做业拿高分对某些特别的女生),并且都会比通常大学讲的深入,事实上,我认为,大学如今的教育为何以为无用,不是太难太理论,而是教的太简单了,简单到已经没有用的地步了,从而根本没有实际意义。(大学联合培训机构,是我所见过的,比大学扩招还要搞笑的事情)好比快速排序,SGI STL作了很是多的优化来保证不管在何时,都不会退化到n2,在分的过程老是分很差时,采用堆排序。在快速排序到作最后几步,为了减小开销而采用插入排序去作哪些立刻就要排好序的部分。而这些策略,并非凭空想象,均可以在高爷爷的著做中找到理论证实,以及网上的各类论文,前提是你的数学功底足够(固然这里实践在前仍是理论在前这个实在是没有讨论的意义)。因此,理论不是没有用,只是本身学的太肤浅。实践也不是没有用,只是本身没有考虑那么多的状况,想的太简单而已。

固然,这个可能又会引发另外一个庞大的问题,“不要重复制做轮子”,不过这个已经大大超出这篇文章的范围了。我本身的见解是,STL是为了实现最基本的最通用的东东的,而实际过程当中,咱们每每有本身的特殊性。而这些特殊性是STL不可能设计时都给咱们考虑周全的。也就是咱们极可能须要扩展,重写部分以适合咱们的须要。固然,如今离这些目标还很远很远很远。

相关文章
相关标签/搜索