算法在学术界的定义是:算法是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制。也就是说,能够对一定规范的输入,在有限时间内获得所要求的输出。
当然如果你觉得以上这个定义过于晦涩,表示完全看不懂。没关系,我们下面还有一个比较科普点的版本。
算法就是为了解决某一特定问题而采用的一种方法。
这里的特定问题有很多种,常见一点的有诸如排序问题、散列问题、二叉树问题,不常见的有排序网络问题、傅里叶变换问题、旅行商问题等。
在这个世界上对这些问题或多或少会存在那么一种或者几种解决的方法,这个也就是我们所谓的算法。当然还有些问题可能没有特定的算法(NP问题),对于这类神奇的问题我们后面会另作讨论。
就排序问题而言,存在很多的算法可以很好的解决这类问题,经常会用到的有选择排序、快速排序(常规排序算法中最快的)、桶排序(非常规排序算法)。这些算法都是一些很常见的算法,同时也是合格的计算机专业学生必须要掌握的基本知识之一。
接下来,我们来点深奥的东西吧!
算法其实是有好坏之分的。有的算法天生效率上就要快一些,而有的算法从来都是低人一等。这个是由算法的基因所决定的,可以在一定程度上被改善,但是无法被改变。
那么如何衡量一个算法的好坏呢?
这个就需要比较专业的计算机知识了。在算法这门学科中,衡量算法的好坏有两个标准,分别是时间复杂度和空间复杂度。这是贯彻整个计算机学科中最为重要的两个概念,同时也是衡量一个算法好坏的两杆尺子。
只要彻底弄明白了这两样东西,你的计算机造诣也就超越了很多计算机专业毕业的学生了。在将来的工作中,遇到任何一个算法,你只要拿出这两把尺子来丈量一下,心里就有底了,知道这个算法的效率如何,适用于什么情况。
这个时候的你,基本上达到了专家的水平,能将很多计算机专业毕业的本科生都比下去。
时间复杂度,指的是一个算法要完成任务,所需要消耗的时间,这通常用该算法需要计算的次数来表示。
同样一个问题,如果一个算法所要运算的次数多,那么这个算法的时间复杂度就大,可能就不是个好算法,反之如果一个算法几步之内就能搞定问题,那说明这个算法的时间复杂度小,极有可能是个好算法。
空间复杂度,指的是一个算法要完成任务,所需要占有内存空间的大小。
因为在算法执行的过程中,有一些中间过程生成的临时数据可能会占有一定的存储空间,而往往计算机的存储空间是有限的,也就是说空间资源是稀缺的,所以这一部分也是衡量一个算法好坏的标准。
对空间复杂度的讨论,往往在一些大数据量的领域中比较适用。基于本文的内容科普性质较强,学术性质偏弱,并且空间复杂度与本书的内容联系不是很紧密,所以这里对空间复杂度不做过多的讨论,而是将更多的精力集中在时间复杂度上。
现在我们就以排序问题为例,用三种不同的排序算法,对一组杂乱无章的数据进行排序,从而简单的介绍一下各种算法在时间复杂度上的区别。
6、15、3、80、43、66、21、18
我们可以看出,以上8个数字的分布是极为混乱的,现在我们要对着数字从小到大进行排序,可供选择的算法有选择排序、快速排序和桶排序。
本着简明扼要并且尽量让大家不致于看着看着就打瞌睡的原则,我们对这些排序算法的思路和具体运行步骤就不详细介绍了。我们仅仅将以上三种算法平均的时间复杂度列举如下:
选择排序: N * N
快速排序: N * logN(此处的对数以2为底)
桶排序: N
我来简单解释一下这些字母和乘除符号的意思。对于一个具有N个数字的数列进行排序,选择排序需要进行N * N次运算,快速排序需要进行 N * logN次运算,而桶排序,需要进行运算的次数最少,只要N次就够了。
我们将这三种算法的时间复杂度适用于以上的8个数字的数列,不难的得出一下答案。
选择排序:8 * 8 = 64次
快速排序: 8 * log8= 24次
桶排序: 8次
这样一来,我们发现在有着8个数字的数列中,选择排序所需要计算的次数最多,桶排序所需要计算的次数最少。从效率上而言,快速排序的效率是选择排序的3倍,而桶排序的效率是选择排序的8倍。
在以上的例子中,进行排序的数字比较少,完全体现不出算法的不同在效率上的天壤之别。
但是,如果以上数字不是8个而是1024个,那么结果就成了:快速排序的效率是选择排序的10倍,而桶排序的效率是选择排序的1024倍!(是不是很惊讶?)
随着数据量的增大,效率高的算法和效率低的算法所体现出来的在效率上差异也就越来越大。
由此可见,选择一个好的算法对程序而言有多么重要。
当然也有人会问,既然桶排序算法效率这么高,那其他的排序算法岂不是没有市场了吗,以后在所有的程序中全部使用桶排序算法就皆大欢喜了。
哦,不好意思,我忘记交代了。
仅仅从时间复杂度上考虑,桶排序确实是效率最高的排序算法,没有之一。但是主席曾说过,“具体问题,具体分析”。在面对复杂且多变化的实际情况中,要考虑的因素很多,对算法的选用也就要因地制宜了。
比如说选择排序虽然效率不高,但是这个算法的思想非常简单,实现起来也很容易,在数据量不大程序员水平也不是很高的情况下,是一种很好的选择;
快速排序虽然效率上略高一筹,但是这个算法的思想有点复杂,实现起来不容易,程序出错的几率也很大,只有在数据量很大,程序员水平较高的情况下,才用使用这种算法的必要;
至于桶排序算法,这其实是非常规排序算法的一种,因为要实现这个算法,对数据的要求比较严格,而且占用内存空间(即空间复杂度)相当大,虽然这个算法运算速度非常快,但是这个是以牺牲了其他方面为基础的,所以最终在程序中使用不是很多。
这样对比下来,我们就发现,在实践中,每种排序算法都有自己的优缺点。所以在实际工作中,选择最适合的算法,而不是效率最高或者是最易于实现的算法,就是对工程师水平最大的考验。
只有算法功底扎实并且经验丰富的工程师才能根据问题的不同,找到那个最合适的算法。
当大家看到这里就会明白,至于安德森口中说的,要将马赛克浏览器的性能提高十倍以上,从理论上而言是绝对可行的。
接下来,我们还要扯一些题外话。
这主要是针对上文提到的“有些问题可能没有特定的算法”这一句话做一些内容上补充,同时也希望能将计算机这门学科中更为深奥的一些东西在这里展示给大家。
基于以下内容跟本文的关系不大,所以……有兴趣的童鞋请接着往下看。
刚刚我们说到,算法是计算机科学中最为深奥最为晦涩,同时也是最为核心的领域。
现在我跟大家解释一下,我为什么要这么说。
在这个世界上有这么一部分人,他们精通Flash制作、3D设计、场景合成等多方面的技能,可以创作出一些精美绝伦的作品,以至于大家都觉得他们很厉害,算得上计算机领域高手级别的人物了。
但是这部分人心里非常清楚,他们所懂得不过是计算机的一些皮毛,他们操作计算机,他们进行创作,还要依靠应用程序的帮助。他们觉得那些能编写应用程序的才是计算机领域的高手。
接下来我们再看看能编写应用程序的高手们,他们又是怎么想的。
这些程序高手他们可以编写出功能强大、简单易用并且流行一时的程序,比如说Flash制作工具、3D设计软件等,但是他们心里也知道,他们懂得不过是计算机的血和肉,因为他们在编写应用软件的工程中,可能会用到一些算法,而这些算法都是从那些绝顶高手那里来的。
至于那些绝顶高手,他们根本就对这些应用程序不屑一顾,因为他们知道计算机的本质是算法,他们知道随着时间的流逝,应用程序、编程语言这类的东西都会最终消逝,只有那些算法才能与时间抗衡,成为恒久不变的经典。